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.client; 019 020import static org.junit.Assert.assertArrayEquals; 021import static org.junit.Assert.assertEquals; 022import static org.junit.Assert.assertFalse; 023import static org.junit.Assert.assertNotNull; 024import static org.junit.Assert.assertNull; 025import static org.junit.Assert.assertTrue; 026import static org.junit.Assert.fail; 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Collection; 031import java.util.LinkedList; 032import java.util.List; 033import java.util.Map; 034import java.util.NavigableMap; 035import java.util.concurrent.Callable; 036import java.util.concurrent.ExecutorService; 037import java.util.concurrent.Executors; 038import java.util.concurrent.atomic.AtomicReference; 039import org.apache.commons.lang3.ArrayUtils; 040import org.apache.hadoop.conf.Configuration; 041import org.apache.hadoop.fs.Path; 042import org.apache.hadoop.hbase.Cell; 043import org.apache.hadoop.hbase.CellScanner; 044import org.apache.hadoop.hbase.CellUtil; 045import org.apache.hadoop.hbase.CompareOperator; 046import org.apache.hadoop.hbase.DoNotRetryIOException; 047import org.apache.hadoop.hbase.HBaseClassTestRule; 048import org.apache.hadoop.hbase.HConstants; 049import org.apache.hadoop.hbase.HRegionLocation; 050import org.apache.hadoop.hbase.KeyValue; 051import org.apache.hadoop.hbase.PrivateCellUtil; 052import org.apache.hadoop.hbase.ServerName; 053import org.apache.hadoop.hbase.TableName; 054import org.apache.hadoop.hbase.TableNameTestRule; 055import org.apache.hadoop.hbase.Waiter; 056import org.apache.hadoop.hbase.client.metrics.ScanMetrics; 057import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint; 058import org.apache.hadoop.hbase.filter.BinaryComparator; 059import org.apache.hadoop.hbase.filter.Filter; 060import org.apache.hadoop.hbase.filter.FilterList; 061import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter; 062import org.apache.hadoop.hbase.filter.InclusiveStopFilter; 063import org.apache.hadoop.hbase.filter.KeyOnlyFilter; 064import org.apache.hadoop.hbase.filter.QualifierFilter; 065import org.apache.hadoop.hbase.filter.RegexStringComparator; 066import org.apache.hadoop.hbase.filter.RowFilter; 067import org.apache.hadoop.hbase.filter.SubstringComparator; 068import org.apache.hadoop.hbase.filter.ValueFilter; 069import org.apache.hadoop.hbase.io.TimeRange; 070import org.apache.hadoop.hbase.io.hfile.BlockCache; 071import org.apache.hadoop.hbase.io.hfile.CacheConfig; 072import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel; 073import org.apache.hadoop.hbase.protobuf.ProtobufUtil; 074import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto; 075import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType; 076import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MultiRowMutationService; 077import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsRequest; 078import org.apache.hadoop.hbase.regionserver.HRegion; 079import org.apache.hadoop.hbase.regionserver.HRegionServer; 080import org.apache.hadoop.hbase.regionserver.HStore; 081import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException; 082import org.apache.hadoop.hbase.testclassification.ClientTests; 083import org.apache.hadoop.hbase.testclassification.LargeTests; 084import org.apache.hadoop.hbase.util.Bytes; 085import org.apache.hadoop.hbase.util.CommonFSUtils; 086import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 087import org.apache.hadoop.hbase.util.FSUtils; 088import org.junit.AfterClass; 089import org.junit.ClassRule; 090import org.junit.Ignore; 091import org.junit.Rule; 092import org.junit.Test; 093import org.junit.experimental.categories.Category; 094import org.junit.runner.RunWith; 095import org.junit.runners.Parameterized; 096import org.slf4j.Logger; 097import org.slf4j.LoggerFactory; 098 099/** 100 * Run tests that use the HBase clients; {@link Table}. 101 * Sets up the HBase mini cluster once at start and runs through all client tests. 102 * Each creates a table named for the method and does its stuff against that. 103 * 104 * Parameterized to run with different registry implementations. 105 */ 106@Category({LargeTests.class, ClientTests.class}) 107@SuppressWarnings ("deprecation") 108@RunWith(Parameterized.class) 109public class TestFromClientSide5 extends FromClientSideBase { 110 private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide5.class); 111 112 @ClassRule 113 public static final HBaseClassTestRule CLASS_RULE = 114 HBaseClassTestRule.forClass(TestFromClientSide5.class); 115 @Rule 116 public TableNameTestRule name = new TableNameTestRule(); 117 118 // To keep the child classes happy. 119 TestFromClientSide5() {} 120 121 public TestFromClientSide5(Class registry, int numHedgedReqs) throws Exception { 122 initialize(registry, numHedgedReqs, MultiRowMutationEndpoint.class); 123 } 124 125 @Parameterized.Parameters 126 public static Collection parameters() { 127 return Arrays.asList(new Object[][] { 128 { MasterRegistry.class, 1}, 129 { MasterRegistry.class, 2}, 130 { ZKConnectionRegistry.class, 1} 131 }); 132 } 133 134 @AfterClass public static void tearDownAfterClass() throws Exception { 135 afterClass(); 136 } 137 138 @Test 139 public void testGetClosestRowBefore() throws IOException, InterruptedException { 140 final TableName tableName = name.getTableName(); 141 final byte[] firstRow = Bytes.toBytes("row111"); 142 final byte[] secondRow = Bytes.toBytes("row222"); 143 final byte[] thirdRow = Bytes.toBytes("row333"); 144 final byte[] forthRow = Bytes.toBytes("row444"); 145 final byte[] beforeFirstRow = Bytes.toBytes("row"); 146 final byte[] beforeSecondRow = Bytes.toBytes("row22"); 147 final byte[] beforeThirdRow = Bytes.toBytes("row33"); 148 final byte[] beforeForthRow = Bytes.toBytes("row44"); 149 150 try (Table table = 151 TEST_UTIL.createTable(tableName, 152 new byte[][] { HConstants.CATALOG_FAMILY, Bytes.toBytes("info2") }, 1, 1024); 153 RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 154 155 // set block size to 64 to making 2 kvs into one block, bypassing the walkForwardInSingleRow 156 // in Store.rowAtOrBeforeFromStoreFile 157 String regionName = locator.getAllRegionLocations().get(0).getRegion().getEncodedName(); 158 HRegion region = TEST_UTIL.getRSForFirstRegionInTable(tableName).getRegion(regionName); 159 Put put1 = new Put(firstRow); 160 Put put2 = new Put(secondRow); 161 Put put3 = new Put(thirdRow); 162 Put put4 = new Put(forthRow); 163 byte[] one = new byte[] { 1 }; 164 byte[] two = new byte[] { 2 }; 165 byte[] three = new byte[] { 3 }; 166 byte[] four = new byte[] { 4 }; 167 168 put1.addColumn(HConstants.CATALOG_FAMILY, null, one); 169 put2.addColumn(HConstants.CATALOG_FAMILY, null, two); 170 put3.addColumn(HConstants.CATALOG_FAMILY, null, three); 171 put4.addColumn(HConstants.CATALOG_FAMILY, null, four); 172 table.put(put1); 173 table.put(put2); 174 table.put(put3); 175 table.put(put4); 176 region.flush(true); 177 178 Result result; 179 180 // Test before first that null is returned 181 result = getReverseScanResult(table, beforeFirstRow); 182 assertNull(result); 183 184 // Test at first that first is returned 185 result = getReverseScanResult(table, firstRow); 186 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 187 assertTrue(Bytes.equals(result.getRow(), firstRow)); 188 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), one)); 189 190 // Test in between first and second that first is returned 191 result = getReverseScanResult(table, beforeSecondRow); 192 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 193 assertTrue(Bytes.equals(result.getRow(), firstRow)); 194 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), one)); 195 196 // Test at second make sure second is returned 197 result = getReverseScanResult(table, secondRow); 198 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 199 assertTrue(Bytes.equals(result.getRow(), secondRow)); 200 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), two)); 201 202 // Test in second and third, make sure second is returned 203 result = getReverseScanResult(table, beforeThirdRow); 204 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 205 assertTrue(Bytes.equals(result.getRow(), secondRow)); 206 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), two)); 207 208 // Test at third make sure third is returned 209 result = getReverseScanResult(table, thirdRow); 210 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 211 assertTrue(Bytes.equals(result.getRow(), thirdRow)); 212 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), three)); 213 214 // Test in third and forth, make sure third is returned 215 result = getReverseScanResult(table, beforeForthRow); 216 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 217 assertTrue(Bytes.equals(result.getRow(), thirdRow)); 218 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), three)); 219 220 // Test at forth make sure forth is returned 221 result = getReverseScanResult(table, forthRow); 222 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 223 assertTrue(Bytes.equals(result.getRow(), forthRow)); 224 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), four)); 225 226 // Test after forth make sure forth is returned 227 result = getReverseScanResult(table, Bytes.add(forthRow, one)); 228 assertTrue(result.containsColumn(HConstants.CATALOG_FAMILY, null)); 229 assertTrue(Bytes.equals(result.getRow(), forthRow)); 230 assertTrue(Bytes.equals(result.getValue(HConstants.CATALOG_FAMILY, null), four)); 231 } 232 } 233 234 private Result getReverseScanResult(Table table, byte[] row) throws IOException { 235 Scan scan = new Scan(row); 236 scan.setSmall(true); 237 scan.setReversed(true); 238 scan.setCaching(1); 239 scan.addFamily(HConstants.CATALOG_FAMILY); 240 try (ResultScanner scanner = table.getScanner(scan)) { 241 return scanner.next(); 242 } 243 } 244 245 /** 246 * For HBASE-2156 247 */ 248 @Test 249 public void testScanVariableReuse() { 250 Scan scan = new Scan(); 251 scan.addFamily(FAMILY); 252 scan.addColumn(FAMILY, ROW); 253 254 assertEquals(1, scan.getFamilyMap().get(FAMILY).size()); 255 256 scan = new Scan(); 257 scan.addFamily(FAMILY); 258 259 assertNull(scan.getFamilyMap().get(FAMILY)); 260 assertTrue(scan.getFamilyMap().containsKey(FAMILY)); 261 } 262 263 @Test 264 public void testMultiRowMutation() throws Exception { 265 LOG.info("Starting testMultiRowMutation"); 266 final TableName tableName = name.getTableName(); 267 final byte [] ROW1 = Bytes.toBytes("testRow1"); 268 269 try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) { 270 Put p = new Put(ROW); 271 p.addColumn(FAMILY, QUALIFIER, VALUE); 272 MutationProto m1 = ProtobufUtil.toMutation(MutationType.PUT, p); 273 274 p = new Put(ROW1); 275 p.addColumn(FAMILY, QUALIFIER, VALUE); 276 MutationProto m2 = ProtobufUtil.toMutation(MutationType.PUT, p); 277 278 MutateRowsRequest.Builder mrmBuilder = MutateRowsRequest.newBuilder(); 279 mrmBuilder.addMutationRequest(m1); 280 mrmBuilder.addMutationRequest(m2); 281 MutateRowsRequest mrm = mrmBuilder.build(); 282 CoprocessorRpcChannel channel = t.coprocessorService(ROW); 283 MultiRowMutationService.BlockingInterface service = 284 MultiRowMutationService.newBlockingStub(channel); 285 service.mutateRows(null, mrm); 286 Get g = new Get(ROW); 287 Result r = t.get(g); 288 assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIER))); 289 g = new Get(ROW1); 290 r = t.get(g); 291 assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIER))); 292 } 293 } 294 295 @Test 296 public void testRowMutation() throws Exception { 297 LOG.info("Starting testRowMutation"); 298 final TableName tableName = name.getTableName(); 299 try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) { 300 byte[][] QUALIFIERS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b") }; 301 RowMutations arm = new RowMutations(ROW); 302 Put p = new Put(ROW); 303 p.addColumn(FAMILY, QUALIFIERS[0], VALUE); 304 arm.add(p); 305 t.mutateRow(arm); 306 307 Get g = new Get(ROW); 308 Result r = t.get(g); 309 assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[0]))); 310 311 arm = new RowMutations(ROW); 312 p = new Put(ROW); 313 p.addColumn(FAMILY, QUALIFIERS[1], VALUE); 314 arm.add(p); 315 Delete d = new Delete(ROW); 316 d.addColumns(FAMILY, QUALIFIERS[0]); 317 arm.add(d); 318 // TODO: Trying mutateRow again. The batch was failing with a one try only. 319 t.mutateRow(arm); 320 r = t.get(g); 321 assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[1]))); 322 assertNull(r.getValue(FAMILY, QUALIFIERS[0])); 323 324 // Test that we get a region level exception 325 try { 326 arm = new RowMutations(ROW); 327 p = new Put(ROW); 328 p.addColumn(new byte[] { 'b', 'o', 'g', 'u', 's' }, QUALIFIERS[0], VALUE); 329 arm.add(p); 330 t.mutateRow(arm); 331 fail("Expected NoSuchColumnFamilyException"); 332 } catch (NoSuchColumnFamilyException e) { 333 return; 334 } catch (RetriesExhaustedWithDetailsException e) { 335 for (Throwable rootCause : e.getCauses()) { 336 if (rootCause instanceof NoSuchColumnFamilyException) { 337 return; 338 } 339 } 340 throw e; 341 } 342 } 343 } 344 345 @Test 346 public void testBatchAppendWithReturnResultFalse() throws Exception { 347 LOG.info("Starting testBatchAppendWithReturnResultFalse"); 348 final TableName tableName = name.getTableName(); 349 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 350 Append append1 = new Append(Bytes.toBytes("row1")); 351 append1.setReturnResults(false); 352 append1.addColumn(FAMILY, Bytes.toBytes("f1"), Bytes.toBytes("value1")); 353 Append append2 = new Append(Bytes.toBytes("row1")); 354 append2.setReturnResults(false); 355 append2.addColumn(FAMILY, Bytes.toBytes("f1"), Bytes.toBytes("value2")); 356 List<Append> appends = new ArrayList<>(); 357 appends.add(append1); 358 appends.add(append2); 359 Object[] results = new Object[2]; 360 table.batch(appends, results); 361 assertEquals(2, results.length); 362 for (Object r : results) { 363 Result result = (Result) r; 364 assertTrue(result.isEmpty()); 365 } 366 } 367 } 368 369 @Test 370 public void testAppend() throws Exception { 371 LOG.info("Starting testAppend"); 372 final TableName tableName = name.getTableName(); 373 try (Table t = TEST_UTIL.createTable(tableName, FAMILY)) { 374 byte[] v1 = Bytes.toBytes("42"); 375 byte[] v2 = Bytes.toBytes("23"); 376 byte[][] QUALIFIERS = new byte[][]{ 377 Bytes.toBytes("b"), Bytes.toBytes("a"), Bytes.toBytes("c") 378 }; 379 Append a = new Append(ROW); 380 a.addColumn(FAMILY, QUALIFIERS[0], v1); 381 a.addColumn(FAMILY, QUALIFIERS[1], v2); 382 a.setReturnResults(false); 383 assertEmptyResult(t.append(a)); 384 385 a = new Append(ROW); 386 a.addColumn(FAMILY, QUALIFIERS[0], v2); 387 a.addColumn(FAMILY, QUALIFIERS[1], v1); 388 a.addColumn(FAMILY, QUALIFIERS[2], v2); 389 Result r = t.append(a); 390 assertEquals(0, Bytes.compareTo(Bytes.add(v1, v2), r.getValue(FAMILY, QUALIFIERS[0]))); 391 assertEquals(0, Bytes.compareTo(Bytes.add(v2, v1), r.getValue(FAMILY, QUALIFIERS[1]))); 392 // QUALIFIERS[2] previously not exist, verify both value and timestamp are correct 393 assertEquals(0, Bytes.compareTo(v2, r.getValue(FAMILY, QUALIFIERS[2]))); 394 assertEquals(r.getColumnLatestCell(FAMILY, QUALIFIERS[0]).getTimestamp(), 395 r.getColumnLatestCell(FAMILY, QUALIFIERS[2]).getTimestamp()); 396 } 397 } 398 private List<Result> doAppend(final boolean walUsed) throws IOException { 399 LOG.info("Starting testAppend, walUsed is " + walUsed); 400 final TableName TABLENAME = 401 TableName.valueOf(walUsed ? "testAppendWithWAL" : "testAppendWithoutWAL"); 402 try (Table t = TEST_UTIL.createTable(TABLENAME, FAMILY)) { 403 final byte[] row1 = Bytes.toBytes("c"); 404 final byte[] row2 = Bytes.toBytes("b"); 405 final byte[] row3 = Bytes.toBytes("a"); 406 final byte[] qual = Bytes.toBytes("qual"); 407 Put put_0 = new Put(row2); 408 put_0.addColumn(FAMILY, qual, Bytes.toBytes("put")); 409 Put put_1 = new Put(row3); 410 put_1.addColumn(FAMILY, qual, Bytes.toBytes("put")); 411 Append append_0 = new Append(row1); 412 append_0.addColumn(FAMILY, qual, Bytes.toBytes("i")); 413 Append append_1 = new Append(row1); 414 append_1.addColumn(FAMILY, qual, Bytes.toBytes("k")); 415 Append append_2 = new Append(row1); 416 append_2.addColumn(FAMILY, qual, Bytes.toBytes("e")); 417 if (!walUsed) { 418 append_2.setDurability(Durability.SKIP_WAL); 419 } 420 Append append_3 = new Append(row1); 421 append_3.addColumn(FAMILY, qual, Bytes.toBytes("a")); 422 Scan s = new Scan(); 423 s.setCaching(1); 424 t.append(append_0); 425 t.put(put_0); 426 t.put(put_1); 427 List<Result> results = new LinkedList<>(); 428 try (ResultScanner scanner = t.getScanner(s)) { 429 t.append(append_1); 430 t.append(append_2); 431 t.append(append_3); 432 for (Result r : scanner) { 433 results.add(r); 434 } 435 } 436 TEST_UTIL.deleteTable(TABLENAME); 437 return results; 438 } 439 } 440 441 @Test 442 public void testAppendWithoutWAL() throws Exception { 443 List<Result> resultsWithWal = doAppend(true); 444 List<Result> resultsWithoutWal = doAppend(false); 445 assertEquals(resultsWithWal.size(), resultsWithoutWal.size()); 446 for (int i = 0; i != resultsWithWal.size(); ++i) { 447 Result resultWithWal = resultsWithWal.get(i); 448 Result resultWithoutWal = resultsWithoutWal.get(i); 449 assertEquals(resultWithWal.rawCells().length, resultWithoutWal.rawCells().length); 450 for (int j = 0; j != resultWithWal.rawCells().length; ++j) { 451 Cell cellWithWal = resultWithWal.rawCells()[j]; 452 Cell cellWithoutWal = resultWithoutWal.rawCells()[j]; 453 assertArrayEquals(CellUtil.cloneRow(cellWithWal), CellUtil.cloneRow(cellWithoutWal)); 454 assertArrayEquals(CellUtil.cloneFamily(cellWithWal), CellUtil.cloneFamily(cellWithoutWal)); 455 assertArrayEquals(CellUtil.cloneQualifier(cellWithWal), 456 CellUtil.cloneQualifier(cellWithoutWal)); 457 assertArrayEquals(CellUtil.cloneValue(cellWithWal), CellUtil.cloneValue(cellWithoutWal)); 458 } 459 } 460 } 461 462 @Test 463 public void testClientPoolRoundRobin() throws IOException { 464 final TableName tableName = name.getTableName(); 465 466 int poolSize = 3; 467 int numVersions = poolSize * 2; 468 Configuration conf = TEST_UTIL.getConfiguration(); 469 conf.set(HConstants.HBASE_CLIENT_IPC_POOL_TYPE, "round-robin"); 470 conf.setInt(HConstants.HBASE_CLIENT_IPC_POOL_SIZE, poolSize); 471 472 try (Table table = 473 TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, Integer.MAX_VALUE)) { 474 475 final long ts = EnvironmentEdgeManager.currentTime(); 476 Get get = new Get(ROW); 477 get.addColumn(FAMILY, QUALIFIER); 478 get.readAllVersions(); 479 480 for (int versions = 1; versions <= numVersions; versions++) { 481 Put put = new Put(ROW); 482 put.addColumn(FAMILY, QUALIFIER, ts + versions, VALUE); 483 table.put(put); 484 485 Result result = table.get(get); 486 NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY) 487 .get(QUALIFIER); 488 489 assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":" 490 + Bytes.toString(QUALIFIER) + " did not match", versions, navigableMap.size()); 491 for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) { 492 assertTrue("The value at time " + entry.getKey() 493 + " did not match what was put", 494 Bytes.equals(VALUE, entry.getValue())); 495 } 496 } 497 } 498 } 499 500 @Ignore ("Flakey: HBASE-8989") @Test 501 public void testClientPoolThreadLocal() throws IOException { 502 final TableName tableName = name.getTableName(); 503 504 int poolSize = Integer.MAX_VALUE; 505 int numVersions = 3; 506 Configuration conf = TEST_UTIL.getConfiguration(); 507 conf.set(HConstants.HBASE_CLIENT_IPC_POOL_TYPE, "thread-local"); 508 conf.setInt(HConstants.HBASE_CLIENT_IPC_POOL_SIZE, poolSize); 509 510 try (final Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, 3)) { 511 512 final long ts = EnvironmentEdgeManager.currentTime(); 513 final Get get = new Get(ROW); 514 get.addColumn(FAMILY, QUALIFIER); 515 get.readAllVersions(); 516 517 for (int versions = 1; versions <= numVersions; versions++) { 518 Put put = new Put(ROW); 519 put.addColumn(FAMILY, QUALIFIER, ts + versions, VALUE); 520 table.put(put); 521 522 Result result = table.get(get); 523 NavigableMap<Long, byte[]> navigableMap = result.getMap().get(FAMILY) 524 .get(QUALIFIER); 525 526 assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":" 527 + Bytes.toString(QUALIFIER) + " did not match", versions, navigableMap.size()); 528 for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) { 529 assertTrue("The value at time " + entry.getKey() 530 + " did not match what was put", 531 Bytes.equals(VALUE, entry.getValue())); 532 } 533 } 534 535 final Object waitLock = new Object(); 536 ExecutorService executorService = Executors.newFixedThreadPool(numVersions); 537 final AtomicReference<AssertionError> error = new AtomicReference<>(null); 538 for (int versions = numVersions; versions < numVersions * 2; versions++) { 539 final int versionsCopy = versions; 540 executorService.submit((Callable<Void>) () -> { 541 try { 542 Put put = new Put(ROW); 543 put.addColumn(FAMILY, QUALIFIER, ts + versionsCopy, VALUE); 544 table.put(put); 545 546 Result result = table.get(get); 547 NavigableMap<Long, byte[]> navigableMap = result.getMap() 548 .get(FAMILY).get(QUALIFIER); 549 550 assertEquals("The number of versions of '" + Bytes.toString(FAMILY) + ":" 551 + Bytes.toString(QUALIFIER) + " did not match " + versionsCopy, versionsCopy, 552 navigableMap.size()); 553 for (Map.Entry<Long, byte[]> entry : navigableMap.entrySet()) { 554 assertTrue("The value at time " + entry.getKey() 555 + " did not match what was put", 556 Bytes.equals(VALUE, entry.getValue())); 557 } 558 synchronized (waitLock) { 559 waitLock.wait(); 560 } 561 } catch (Exception ignored) { 562 } catch (AssertionError e) { 563 // the error happens in a thread, it won't fail the test, 564 // need to pass it to the caller for proper handling. 565 error.set(e); 566 LOG.error(e.toString(), e); 567 } 568 569 return null; 570 }); 571 } 572 synchronized (waitLock) { 573 waitLock.notifyAll(); 574 } 575 executorService.shutdownNow(); 576 assertNull(error.get()); 577 } 578 } 579 580 @Test 581 public void testCheckAndPut() throws IOException { 582 final byte [] anotherrow = Bytes.toBytes("anotherrow"); 583 final byte [] value2 = Bytes.toBytes("abcd"); 584 585 try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) { 586 Put put1 = new Put(ROW); 587 put1.addColumn(FAMILY, QUALIFIER, VALUE); 588 589 // row doesn't exist, so using non-null value should be considered "not match". 590 boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 591 .ifEquals(VALUE).thenPut(put1); 592 assertFalse(ok); 593 594 // row doesn't exist, so using "ifNotExists" should be considered "match". 595 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1); 596 assertTrue(ok); 597 598 // row now exists, so using "ifNotExists" should be considered "not match". 599 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put1); 600 assertFalse(ok); 601 602 Put put2 = new Put(ROW); 603 put2.addColumn(FAMILY, QUALIFIER, value2); 604 605 // row now exists, use the matching value to check 606 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(VALUE).thenPut(put2); 607 assertTrue(ok); 608 609 Put put3 = new Put(anotherrow); 610 put3.addColumn(FAMILY, QUALIFIER, VALUE); 611 612 // try to do CheckAndPut on different rows 613 try { 614 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifEquals(value2).thenPut(put3); 615 fail("trying to check and modify different rows should have failed."); 616 } catch (Exception ignored) { 617 } 618 } 619 } 620 621 @Test 622 public void testCheckAndMutateWithTimeRange() throws IOException { 623 try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) { 624 final long ts = System.currentTimeMillis() / 2; 625 Put put = new Put(ROW); 626 put.addColumn(FAMILY, QUALIFIER, ts, VALUE); 627 628 boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 629 .ifNotExists() 630 .thenPut(put); 631 assertTrue(ok); 632 633 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 634 .timeRange(TimeRange.at(ts + 10000)) 635 .ifEquals(VALUE) 636 .thenPut(put); 637 assertFalse(ok); 638 639 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 640 .timeRange(TimeRange.from(ts + 10000)) 641 .ifEquals(VALUE) 642 .thenPut(put); 643 assertFalse(ok); 644 645 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 646 .timeRange(TimeRange.between(ts + 10000, ts + 20000)) 647 .ifEquals(VALUE) 648 .thenPut(put); 649 assertFalse(ok); 650 651 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 652 .timeRange(TimeRange.until(ts)) 653 .ifEquals(VALUE) 654 .thenPut(put); 655 assertFalse(ok); 656 657 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 658 .timeRange(TimeRange.at(ts)) 659 .ifEquals(VALUE) 660 .thenPut(put); 661 assertTrue(ok); 662 663 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 664 .timeRange(TimeRange.from(ts)) 665 .ifEquals(VALUE) 666 .thenPut(put); 667 assertTrue(ok); 668 669 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 670 .timeRange(TimeRange.between(ts, ts + 20000)) 671 .ifEquals(VALUE) 672 .thenPut(put); 673 assertTrue(ok); 674 675 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 676 .timeRange(TimeRange.until(ts + 10000)) 677 .ifEquals(VALUE) 678 .thenPut(put); 679 assertTrue(ok); 680 681 RowMutations rm = new RowMutations(ROW) 682 .add((Mutation) put); 683 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 684 .timeRange(TimeRange.at(ts + 10000)) 685 .ifEquals(VALUE) 686 .thenMutate(rm); 687 assertFalse(ok); 688 689 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 690 .timeRange(TimeRange.at(ts)) 691 .ifEquals(VALUE) 692 .thenMutate(rm); 693 assertTrue(ok); 694 695 Delete delete = new Delete(ROW) 696 .addColumn(FAMILY, QUALIFIER); 697 698 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 699 .timeRange(TimeRange.at(ts + 10000)) 700 .ifEquals(VALUE) 701 .thenDelete(delete); 702 assertFalse(ok); 703 704 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 705 .timeRange(TimeRange.at(ts)) 706 .ifEquals(VALUE) 707 .thenDelete(delete); 708 assertTrue(ok); 709 } 710 } 711 712 @Test 713 public void testCheckAndPutWithCompareOp() throws IOException { 714 final byte [] value1 = Bytes.toBytes("aaaa"); 715 final byte [] value2 = Bytes.toBytes("bbbb"); 716 final byte [] value3 = Bytes.toBytes("cccc"); 717 final byte [] value4 = Bytes.toBytes("dddd"); 718 719 try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) { 720 721 Put put2 = new Put(ROW); 722 put2.addColumn(FAMILY, QUALIFIER, value2); 723 724 Put put3 = new Put(ROW); 725 put3.addColumn(FAMILY, QUALIFIER, value3); 726 727 // row doesn't exist, so using "ifNotExists" should be considered "match". 728 boolean ok = 729 table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER).ifNotExists().thenPut(put2); 730 assertTrue(ok); 731 732 // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL 733 // turns out "match" 734 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 735 .ifMatches(CompareOperator.GREATER, value1).thenPut(put2); 736 assertFalse(ok); 737 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 738 .ifMatches(CompareOperator.EQUAL, value1).thenPut(put2); 739 assertFalse(ok); 740 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 741 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenPut(put2); 742 assertFalse(ok); 743 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 744 .ifMatches(CompareOperator.LESS, value1).thenPut(put2); 745 assertTrue(ok); 746 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 747 .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenPut(put2); 748 assertTrue(ok); 749 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 750 .ifMatches(CompareOperator.NOT_EQUAL, value1).thenPut(put3); 751 assertTrue(ok); 752 753 // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL 754 // turns out "match" 755 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 756 .ifMatches(CompareOperator.LESS, value4).thenPut(put3); 757 assertFalse(ok); 758 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 759 .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenPut(put3); 760 assertFalse(ok); 761 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 762 .ifMatches(CompareOperator.EQUAL, value4).thenPut(put3); 763 assertFalse(ok); 764 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 765 .ifMatches(CompareOperator.GREATER, value4).thenPut(put3); 766 assertTrue(ok); 767 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 768 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenPut(put3); 769 assertTrue(ok); 770 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 771 .ifMatches(CompareOperator.NOT_EQUAL, value4).thenPut(put2); 772 assertTrue(ok); 773 774 // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL 775 // turns out "match" 776 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 777 .ifMatches(CompareOperator.GREATER, value2).thenPut(put2); 778 assertFalse(ok); 779 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 780 .ifMatches(CompareOperator.NOT_EQUAL, value2).thenPut(put2); 781 assertFalse(ok); 782 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 783 .ifMatches(CompareOperator.LESS, value2).thenPut(put2); 784 assertFalse(ok); 785 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 786 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenPut(put2); 787 assertTrue(ok); 788 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 789 .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenPut(put2); 790 assertTrue(ok); 791 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 792 .ifMatches(CompareOperator.EQUAL, value2).thenPut(put3); 793 assertTrue(ok); 794 } 795 } 796 797 @Test 798 public void testCheckAndDelete() throws IOException { 799 final byte [] value1 = Bytes.toBytes("aaaa"); 800 801 try (Table table = TEST_UTIL.createTable(name.getTableName(), 802 FAMILY)) { 803 804 Put put = new Put(ROW); 805 put.addColumn(FAMILY, QUALIFIER, value1); 806 table.put(put); 807 808 Delete delete = new Delete(ROW); 809 delete.addColumns(FAMILY, QUALIFIER); 810 811 boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 812 .ifEquals(value1).thenDelete(delete); 813 assertTrue(ok); 814 } 815 } 816 817 @Test 818 public void testCheckAndDeleteWithCompareOp() throws IOException { 819 final byte [] value1 = Bytes.toBytes("aaaa"); 820 final byte [] value2 = Bytes.toBytes("bbbb"); 821 final byte [] value3 = Bytes.toBytes("cccc"); 822 final byte [] value4 = Bytes.toBytes("dddd"); 823 824 try (Table table = TEST_UTIL.createTable(name.getTableName(), 825 FAMILY)) { 826 827 Put put2 = new Put(ROW); 828 put2.addColumn(FAMILY, QUALIFIER, value2); 829 table.put(put2); 830 831 Put put3 = new Put(ROW); 832 put3.addColumn(FAMILY, QUALIFIER, value3); 833 834 Delete delete = new Delete(ROW); 835 delete.addColumns(FAMILY, QUALIFIER); 836 837 // cell = "bbbb", using "aaaa" to compare only LESS/LESS_OR_EQUAL/NOT_EQUAL 838 // turns out "match" 839 boolean ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 840 .ifMatches(CompareOperator.GREATER, value1).thenDelete(delete); 841 assertFalse(ok); 842 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 843 .ifMatches(CompareOperator.EQUAL, value1).thenDelete(delete); 844 assertFalse(ok); 845 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 846 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value1).thenDelete(delete); 847 assertFalse(ok); 848 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 849 .ifMatches(CompareOperator.LESS, value1).thenDelete(delete); 850 assertTrue(ok); 851 table.put(put2); 852 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 853 .ifMatches(CompareOperator.LESS_OR_EQUAL, value1).thenDelete(delete); 854 assertTrue(ok); 855 table.put(put2); 856 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 857 .ifMatches(CompareOperator.NOT_EQUAL, value1).thenDelete(delete); 858 assertTrue(ok); 859 860 // cell = "cccc", using "dddd" to compare only LARGER/LARGER_OR_EQUAL/NOT_EQUAL 861 // turns out "match" 862 table.put(put3); 863 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 864 .ifMatches(CompareOperator.LESS, value4).thenDelete(delete); 865 assertFalse(ok); 866 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 867 .ifMatches(CompareOperator.LESS_OR_EQUAL, value4).thenDelete(delete); 868 assertFalse(ok); 869 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 870 .ifMatches(CompareOperator.EQUAL, value4).thenDelete(delete); 871 assertFalse(ok); 872 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 873 .ifMatches(CompareOperator.GREATER, value4).thenDelete(delete); 874 assertTrue(ok); 875 table.put(put3); 876 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 877 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value4).thenDelete(delete); 878 assertTrue(ok); 879 table.put(put3); 880 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 881 .ifMatches(CompareOperator.NOT_EQUAL, value4).thenDelete(delete); 882 assertTrue(ok); 883 884 // cell = "bbbb", using "bbbb" to compare only GREATER_OR_EQUAL/LESS_OR_EQUAL/EQUAL 885 // turns out "match" 886 table.put(put2); 887 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 888 .ifMatches(CompareOperator.GREATER, value2).thenDelete(delete); 889 assertFalse(ok); 890 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 891 .ifMatches(CompareOperator.NOT_EQUAL, value2).thenDelete(delete); 892 assertFalse(ok); 893 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 894 .ifMatches(CompareOperator.LESS, value2).thenDelete(delete); 895 assertFalse(ok); 896 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 897 .ifMatches(CompareOperator.GREATER_OR_EQUAL, value2).thenDelete(delete); 898 assertTrue(ok); 899 table.put(put2); 900 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 901 .ifMatches(CompareOperator.LESS_OR_EQUAL, value2).thenDelete(delete); 902 assertTrue(ok); 903 table.put(put2); 904 ok = table.checkAndMutate(ROW, FAMILY).qualifier(QUALIFIER) 905 .ifMatches(CompareOperator.EQUAL, value2).thenDelete(delete); 906 assertTrue(ok); 907 } 908 } 909 910 /** 911 * Test ScanMetrics 912 */ 913 @Test 914 @SuppressWarnings({"unused", "checkstyle:EmptyBlock"}) 915 public void testScanMetrics() throws Exception { 916 final TableName tableName = name.getTableName(); 917 918 // Set up test table: 919 // Create table: 920 try (Table ht = TEST_UTIL.createMultiRegionTable(tableName, FAMILY)) { 921 int numOfRegions; 922 try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 923 numOfRegions = r.getStartKeys().length; 924 } 925 // Create 3 rows in the table, with rowkeys starting with "zzz*" so that 926 // scan are forced to hit all the regions. 927 Put put1 = new Put(Bytes.toBytes("zzz1")); 928 put1.addColumn(FAMILY, QUALIFIER, VALUE); 929 Put put2 = new Put(Bytes.toBytes("zzz2")); 930 put2.addColumn(FAMILY, QUALIFIER, VALUE); 931 Put put3 = new Put(Bytes.toBytes("zzz3")); 932 put3.addColumn(FAMILY, QUALIFIER, VALUE); 933 ht.put(Arrays.asList(put1, put2, put3)); 934 935 Scan scan1 = new Scan(); 936 int numRecords = 0; 937 try (ResultScanner scanner = ht.getScanner(scan1)) { 938 for (Result result : scanner) { 939 numRecords++; 940 } 941 942 LOG.info("test data has " + numRecords + " records."); 943 944 // by default, scan metrics collection is turned off 945 assertNull(scanner.getScanMetrics()); 946 } 947 948 // turn on scan metrics 949 Scan scan2 = new Scan(); 950 scan2.setScanMetricsEnabled(true); 951 scan2.setCaching(numRecords + 1); 952 try (ResultScanner scanner = ht.getScanner(scan2)) { 953 for (Result result : scanner.next(numRecords - 1)) { 954 } 955 scanner.close(); 956 // closing the scanner will set the metrics. 957 assertNotNull(scanner.getScanMetrics()); 958 } 959 960 // set caching to 1, because metrics are collected in each roundtrip only 961 scan2 = new Scan(); 962 scan2.setScanMetricsEnabled(true); 963 scan2.setCaching(1); 964 try (ResultScanner scanner = ht.getScanner(scan2)) { 965 // per HBASE-5717, this should still collect even if you don't run all the way to 966 // the end of the scanner. So this is asking for 2 of the 3 rows we inserted. 967 for (Result result : scanner.next(numRecords - 1)) { 968 } 969 ScanMetrics scanMetrics = scanner.getScanMetrics(); 970 assertEquals("Did not access all the regions in the table", numOfRegions, 971 scanMetrics.countOfRegions.get()); 972 } 973 974 // check byte counters 975 scan2 = new Scan(); 976 scan2.setScanMetricsEnabled(true); 977 scan2.setCaching(1); 978 try (ResultScanner scanner = ht.getScanner(scan2)) { 979 int numBytes = 0; 980 for (Result result : scanner.next(1)) { 981 for (Cell cell : result.listCells()) { 982 numBytes += PrivateCellUtil.estimatedSerializedSizeOf(cell); 983 } 984 } 985 scanner.close(); 986 ScanMetrics scanMetrics = scanner.getScanMetrics(); 987 assertEquals("Did not count the result bytes", numBytes, 988 scanMetrics.countOfBytesInResults.get()); 989 } 990 991 // check byte counters on a small scan 992 scan2 = new Scan(); 993 scan2.setScanMetricsEnabled(true); 994 scan2.setCaching(1); 995 scan2.setSmall(true); 996 try (ResultScanner scanner = ht.getScanner(scan2)) { 997 int numBytes = 0; 998 for (Result result : scanner.next(1)) { 999 for (Cell cell : result.listCells()) { 1000 numBytes += PrivateCellUtil.estimatedSerializedSizeOf(cell); 1001 } 1002 } 1003 scanner.close(); 1004 ScanMetrics scanMetrics = scanner.getScanMetrics(); 1005 assertEquals("Did not count the result bytes", numBytes, 1006 scanMetrics.countOfBytesInResults.get()); 1007 } 1008 1009 // now, test that the metrics are still collected even if you don't call close, but do 1010 // run past the end of all the records 1011 /** There seems to be a timing issue here. Comment out for now. Fix when time. 1012 Scan scanWithoutClose = new Scan(); 1013 scanWithoutClose.setCaching(1); 1014 scanWithoutClose.setScanMetricsEnabled(true); 1015 ResultScanner scannerWithoutClose = ht.getScanner(scanWithoutClose); 1016 for (Result result : scannerWithoutClose.next(numRecords + 1)) { 1017 } 1018 ScanMetrics scanMetricsWithoutClose = getScanMetrics(scanWithoutClose); 1019 assertEquals("Did not access all the regions in the table", numOfRegions, 1020 scanMetricsWithoutClose.countOfRegions.get()); 1021 */ 1022 1023 // finally, 1024 // test that the metrics are collected correctly if you both run past all the records, 1025 // AND close the scanner 1026 Scan scanWithClose = new Scan(); 1027 // make sure we can set caching up to the number of a scanned values 1028 scanWithClose.setCaching(numRecords); 1029 scanWithClose.setScanMetricsEnabled(true); 1030 try (ResultScanner scannerWithClose = ht.getScanner(scanWithClose)) { 1031 for (Result result : scannerWithClose.next(numRecords + 1)) { 1032 } 1033 scannerWithClose.close(); 1034 ScanMetrics scanMetricsWithClose = scannerWithClose.getScanMetrics(); 1035 assertEquals("Did not access all the regions in the table", numOfRegions, 1036 scanMetricsWithClose.countOfRegions.get()); 1037 } 1038 } 1039 } 1040 1041 /** 1042 * Tests that cache on write works all the way up from the client-side. 1043 * 1044 * Performs inserts, flushes, and compactions, verifying changes in the block 1045 * cache along the way. 1046 */ 1047 @Test 1048 public void testCacheOnWriteEvictOnClose() throws Exception { 1049 final TableName tableName = name.getTableName(); 1050 byte [] data = Bytes.toBytes("data"); 1051 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 1052 try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 1053 // get the block cache and region 1054 String regionName = locator.getAllRegionLocations().get(0).getRegion().getEncodedName(); 1055 1056 HRegion region = TEST_UTIL.getRSForFirstRegionInTable(tableName) 1057 .getRegion(regionName); 1058 HStore store = region.getStores().iterator().next(); 1059 CacheConfig cacheConf = store.getCacheConfig(); 1060 cacheConf.setCacheDataOnWrite(true); 1061 cacheConf.setEvictOnClose(true); 1062 BlockCache cache = cacheConf.getBlockCache().get(); 1063 1064 // establish baseline stats 1065 long startBlockCount = cache.getBlockCount(); 1066 long startBlockHits = cache.getStats().getHitCount(); 1067 long startBlockMiss = cache.getStats().getMissCount(); 1068 1069 // wait till baseline is stable, (minimal 500 ms) 1070 for (int i = 0; i < 5; i++) { 1071 Thread.sleep(100); 1072 if (startBlockCount != cache.getBlockCount() 1073 || startBlockHits != cache.getStats().getHitCount() 1074 || startBlockMiss != cache.getStats().getMissCount()) { 1075 startBlockCount = cache.getBlockCount(); 1076 startBlockHits = cache.getStats().getHitCount(); 1077 startBlockMiss = cache.getStats().getMissCount(); 1078 i = -1; 1079 } 1080 } 1081 1082 // insert data 1083 Put put = new Put(ROW); 1084 put.addColumn(FAMILY, QUALIFIER, data); 1085 table.put(put); 1086 assertTrue(Bytes.equals(table.get(new Get(ROW)).value(), data)); 1087 1088 // data was in memstore so don't expect any changes 1089 assertEquals(startBlockCount, cache.getBlockCount()); 1090 assertEquals(startBlockHits, cache.getStats().getHitCount()); 1091 assertEquals(startBlockMiss, cache.getStats().getMissCount()); 1092 1093 // flush the data 1094 LOG.debug("Flushing cache"); 1095 region.flush(true); 1096 1097 // expect two more blocks in cache - DATA and ROOT_INDEX 1098 // , no change in hits/misses 1099 long expectedBlockCount = startBlockCount + 2; 1100 long expectedBlockHits = startBlockHits; 1101 long expectedBlockMiss = startBlockMiss; 1102 assertEquals(expectedBlockCount, cache.getBlockCount()); 1103 assertEquals(expectedBlockHits, cache.getStats().getHitCount()); 1104 assertEquals(expectedBlockMiss, cache.getStats().getMissCount()); 1105 // read the data and expect same blocks, one new hit, no misses 1106 assertTrue(Bytes.equals(table.get(new Get(ROW)).value(), data)); 1107 assertEquals(expectedBlockCount, cache.getBlockCount()); 1108 assertEquals(++expectedBlockHits, cache.getStats().getHitCount()); 1109 assertEquals(expectedBlockMiss, cache.getStats().getMissCount()); 1110 // insert a second column, read the row, no new blocks, one new hit 1111 byte[] QUALIFIER2 = Bytes.add(QUALIFIER, QUALIFIER); 1112 byte[] data2 = Bytes.add(data, data); 1113 put = new Put(ROW); 1114 put.addColumn(FAMILY, QUALIFIER2, data2); 1115 table.put(put); 1116 Result r = table.get(new Get(ROW)); 1117 assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER), data)); 1118 assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER2), data2)); 1119 assertEquals(expectedBlockCount, cache.getBlockCount()); 1120 assertEquals(++expectedBlockHits, cache.getStats().getHitCount()); 1121 assertEquals(expectedBlockMiss, cache.getStats().getMissCount()); 1122 // flush, one new block 1123 System.out.println("Flushing cache"); 1124 region.flush(true); 1125 1126 // + 1 for Index Block, +1 for data block 1127 expectedBlockCount += 2; 1128 assertEquals(expectedBlockCount, cache.getBlockCount()); 1129 assertEquals(expectedBlockHits, cache.getStats().getHitCount()); 1130 assertEquals(expectedBlockMiss, cache.getStats().getMissCount()); 1131 // compact, net minus two blocks, two hits, no misses 1132 System.out.println("Compacting"); 1133 assertEquals(2, store.getStorefilesCount()); 1134 store.triggerMajorCompaction(); 1135 region.compact(true); 1136 store.closeAndArchiveCompactedFiles(); 1137 waitForStoreFileCount(store, 1, 10000); // wait 10 seconds max 1138 assertEquals(1, store.getStorefilesCount()); 1139 // evicted two data blocks and two index blocks and compaction does not cache new blocks 1140 expectedBlockCount = 0; 1141 assertEquals(expectedBlockCount, cache.getBlockCount()); 1142 expectedBlockHits += 2; 1143 assertEquals(expectedBlockMiss, cache.getStats().getMissCount()); 1144 assertEquals(expectedBlockHits, cache.getStats().getHitCount()); 1145 // read the row, this should be a cache miss because we don't cache data 1146 // blocks on compaction 1147 r = table.get(new Get(ROW)); 1148 assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER), data)); 1149 assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER2), data2)); 1150 expectedBlockCount += 1; // cached one data block 1151 assertEquals(expectedBlockCount, cache.getBlockCount()); 1152 assertEquals(expectedBlockHits, cache.getStats().getHitCount()); 1153 assertEquals(++expectedBlockMiss, cache.getStats().getMissCount()); 1154 } 1155 } 1156 } 1157 1158 private void waitForStoreFileCount(HStore store, int count, int timeout) 1159 throws InterruptedException { 1160 long start = System.currentTimeMillis(); 1161 while (start + timeout > System.currentTimeMillis() && store.getStorefilesCount() != count) { 1162 Thread.sleep(100); 1163 } 1164 System.out.println("start=" + start + ", now=" + System.currentTimeMillis() + ", cur=" + 1165 store.getStorefilesCount()); 1166 assertEquals(count, store.getStorefilesCount()); 1167 } 1168 1169 /** 1170 * Tests the non cached version of getRegionLocator by moving a region. 1171 */ 1172 @Test 1173 public void testNonCachedGetRegionLocation() throws Exception { 1174 // Test Initialization. 1175 final TableName tableName = name.getTableName(); 1176 byte [] family1 = Bytes.toBytes("f1"); 1177 byte [] family2 = Bytes.toBytes("f2"); 1178 try (Table ignored = TEST_UTIL.createTable(tableName, new byte[][] {family1, family2}, 10); 1179 Admin admin = TEST_UTIL.getAdmin(); 1180 RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 1181 List<HRegionLocation> allRegionLocations = locator.getAllRegionLocations(); 1182 assertEquals(1, allRegionLocations.size()); 1183 RegionInfo regionInfo = allRegionLocations.get(0).getRegion(); 1184 ServerName addrBefore = allRegionLocations.get(0).getServerName(); 1185 // Verify region location before move. 1186 HRegionLocation addrCache = locator.getRegionLocation(regionInfo.getStartKey(), false); 1187 HRegionLocation addrNoCache = locator.getRegionLocation(regionInfo.getStartKey(), true); 1188 1189 assertEquals(addrBefore.getPort(), addrCache.getPort()); 1190 assertEquals(addrBefore.getPort(), addrNoCache.getPort()); 1191 1192 // Make sure more than one server. 1193 if (TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size() <= 1) { 1194 TEST_UTIL.getMiniHBaseCluster().startRegionServer(); 1195 Waiter.waitFor(TEST_UTIL.getConfiguration(), 30000, new Waiter.Predicate<Exception>() { 1196 @Override public boolean evaluate() throws Exception { 1197 return TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size() > 1; 1198 } 1199 }); 1200 } 1201 1202 ServerName addrAfter = null; 1203 // Now move the region to a different server. 1204 for (int i = 0; i < TEST_UTIL.getMiniHBaseCluster().getLiveRegionServerThreads().size(); 1205 i++) { 1206 HRegionServer regionServer = TEST_UTIL.getHBaseCluster().getRegionServer(i); 1207 ServerName addr = regionServer.getServerName(); 1208 if (addr.getPort() != addrBefore.getPort()) { 1209 admin.move(regionInfo.getEncodedNameAsBytes(), addr); 1210 // Wait for the region to move. 1211 Thread.sleep(5000); 1212 addrAfter = addr; 1213 break; 1214 } 1215 } 1216 1217 // Verify the region was moved. 1218 addrCache = locator.getRegionLocation(regionInfo.getStartKey(), false); 1219 addrNoCache = locator.getRegionLocation(regionInfo.getStartKey(), true); 1220 assertNotNull(addrAfter); 1221 assertTrue(addrAfter.getPort() != addrCache.getPort()); 1222 assertEquals(addrAfter.getPort(), addrNoCache.getPort()); 1223 } 1224 } 1225 1226 /** 1227 * Tests getRegionsInRange by creating some regions over which a range of 1228 * keys spans; then changing the key range. 1229 */ 1230 @Test 1231 public void testGetRegionsInRange() throws Exception { 1232 // Test Initialization. 1233 byte [] startKey = Bytes.toBytes("ddc"); 1234 byte [] endKey = Bytes.toBytes("mmm"); 1235 TableName tableName = name.getTableName(); 1236 TEST_UTIL.createMultiRegionTable(tableName, new byte[][] { FAMILY }, 10); 1237 1238 int numOfRegions; 1239 try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 1240 numOfRegions = r.getStartKeys().length; 1241 } 1242 assertEquals(26, numOfRegions); 1243 1244 // Get the regions in this range 1245 List<HRegionLocation> regionsList = getRegionsInRange(tableName, startKey, endKey); 1246 assertEquals(10, regionsList.size()); 1247 1248 // Change the start key 1249 startKey = Bytes.toBytes("fff"); 1250 regionsList = getRegionsInRange(tableName, startKey, endKey); 1251 assertEquals(7, regionsList.size()); 1252 1253 // Change the end key 1254 endKey = Bytes.toBytes("nnn"); 1255 regionsList = getRegionsInRange(tableName, startKey, endKey); 1256 assertEquals(8, regionsList.size()); 1257 1258 // Empty start key 1259 regionsList = getRegionsInRange(tableName, HConstants.EMPTY_START_ROW, endKey); 1260 assertEquals(13, regionsList.size()); 1261 1262 // Empty end key 1263 regionsList = getRegionsInRange(tableName, startKey, HConstants.EMPTY_END_ROW); 1264 assertEquals(21, regionsList.size()); 1265 1266 // Both start and end keys empty 1267 regionsList = getRegionsInRange(tableName, HConstants.EMPTY_START_ROW, 1268 HConstants.EMPTY_END_ROW); 1269 assertEquals(26, regionsList.size()); 1270 1271 // Change the end key to somewhere in the last block 1272 endKey = Bytes.toBytes("zzz1"); 1273 regionsList = getRegionsInRange(tableName, startKey, endKey); 1274 assertEquals(21, regionsList.size()); 1275 1276 // Change the start key to somewhere in the first block 1277 startKey = Bytes.toBytes("aac"); 1278 regionsList = getRegionsInRange(tableName, startKey, endKey); 1279 assertEquals(26, regionsList.size()); 1280 1281 // Make start and end key the same 1282 startKey = Bytes.toBytes("ccc"); 1283 endKey = Bytes.toBytes("ccc"); 1284 regionsList = getRegionsInRange(tableName, startKey, endKey); 1285 assertEquals(1, regionsList.size()); 1286 } 1287 1288 private List<HRegionLocation> getRegionsInRange(TableName tableName, byte[] startKey, 1289 byte[] endKey) throws IOException { 1290 List<HRegionLocation> regionsInRange = new ArrayList<>(); 1291 byte[] currentKey = startKey; 1292 final boolean endKeyIsEndOfTable = Bytes.equals(endKey, HConstants.EMPTY_END_ROW); 1293 try (RegionLocator r = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 1294 do { 1295 HRegionLocation regionLocation = r.getRegionLocation(currentKey); 1296 regionsInRange.add(regionLocation); 1297 currentKey = regionLocation.getRegion().getEndKey(); 1298 } while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW) 1299 && (endKeyIsEndOfTable || Bytes.compareTo(currentKey, endKey) < 0)); 1300 return regionsInRange; 1301 } 1302 } 1303 1304 @Test 1305 public void testJira6912() throws Exception { 1306 final TableName tableName = name.getTableName(); 1307 try (Table foo = TEST_UTIL.createTable(tableName, new byte[][] {FAMILY}, 10)) { 1308 1309 List<Put> puts = new ArrayList<>(); 1310 for (int i = 0; i != 100; i++) { 1311 Put put = new Put(Bytes.toBytes(i)); 1312 put.addColumn(FAMILY, FAMILY, Bytes.toBytes(i)); 1313 puts.add(put); 1314 } 1315 foo.put(puts); 1316 // If i comment this out it works 1317 TEST_UTIL.flush(); 1318 1319 Scan scan = new Scan(); 1320 scan.setStartRow(Bytes.toBytes(1)); 1321 scan.setStopRow(Bytes.toBytes(3)); 1322 scan.addColumn(FAMILY, FAMILY); 1323 scan.setFilter(new RowFilter(CompareOperator.NOT_EQUAL, 1324 new BinaryComparator(Bytes.toBytes(1)))); 1325 1326 try (ResultScanner scanner = foo.getScanner(scan)) { 1327 Result[] bar = scanner.next(100); 1328 assertEquals(1, bar.length); 1329 } 1330 } 1331 } 1332 1333 @Test 1334 public void testScan_NullQualifier() throws IOException { 1335 try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) { 1336 Put put = new Put(ROW); 1337 put.addColumn(FAMILY, QUALIFIER, VALUE); 1338 table.put(put); 1339 1340 put = new Put(ROW); 1341 put.addColumn(FAMILY, null, VALUE); 1342 table.put(put); 1343 LOG.info("Row put"); 1344 1345 Scan scan = new Scan(); 1346 scan.addColumn(FAMILY, null); 1347 1348 ResultScanner scanner = table.getScanner(scan); 1349 Result[] bar = scanner.next(100); 1350 assertEquals(1, bar.length); 1351 assertEquals(1, bar[0].size()); 1352 1353 scan = new Scan(); 1354 scan.addFamily(FAMILY); 1355 1356 scanner = table.getScanner(scan); 1357 bar = scanner.next(100); 1358 assertEquals(1, bar.length); 1359 assertEquals(2, bar[0].size()); 1360 } 1361 } 1362 1363 @Test 1364 public void testNegativeTimestamp() throws IOException { 1365 try (Table table = TEST_UTIL.createTable(name.getTableName(), FAMILY)) { 1366 1367 try { 1368 Put put = new Put(ROW, -1); 1369 put.addColumn(FAMILY, QUALIFIER, VALUE); 1370 table.put(put); 1371 fail("Negative timestamps should not have been allowed"); 1372 } catch (IllegalArgumentException ex) { 1373 assertTrue(ex.getMessage().contains("negative")); 1374 } 1375 1376 try { 1377 Put put = new Put(ROW); 1378 long ts = -1; 1379 put.addColumn(FAMILY, QUALIFIER, ts, VALUE); 1380 table.put(put); 1381 fail("Negative timestamps should not have been allowed"); 1382 } catch (IllegalArgumentException ex) { 1383 assertTrue(ex.getMessage().contains("negative")); 1384 } 1385 1386 try { 1387 Delete delete = new Delete(ROW, -1); 1388 table.delete(delete); 1389 fail("Negative timestamps should not have been allowed"); 1390 } catch (IllegalArgumentException ex) { 1391 assertTrue(ex.getMessage().contains("negative")); 1392 } 1393 1394 try { 1395 Delete delete = new Delete(ROW); 1396 delete.addFamily(FAMILY, -1); 1397 table.delete(delete); 1398 fail("Negative timestamps should not have been allowed"); 1399 } catch (IllegalArgumentException ex) { 1400 assertTrue(ex.getMessage().contains("negative")); 1401 } 1402 1403 try { 1404 Scan scan = new Scan(); 1405 scan.setTimeRange(-1, 1); 1406 table.getScanner(scan); 1407 fail("Negative timestamps should not have been allowed"); 1408 } catch (IllegalArgumentException ex) { 1409 assertTrue(ex.getMessage().contains("negative")); 1410 } 1411 1412 // KeyValue should allow negative timestamps for backwards compat. Otherwise, if the user 1413 // already has negative timestamps in cluster data, HBase won't be able to handle that 1414 try { 1415 new KeyValue(Bytes.toBytes(42), Bytes.toBytes(42), Bytes.toBytes(42), -1, 1416 Bytes.toBytes(42)); 1417 } catch (IllegalArgumentException ex) { 1418 fail("KeyValue SHOULD allow negative timestamps"); 1419 } 1420 1421 } 1422 } 1423 1424 @Test 1425 public void testRawScanRespectsVersions() throws Exception { 1426 final TableName tableName = name.getTableName(); 1427 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 1428 byte[] row = Bytes.toBytes("row"); 1429 1430 // put the same row 4 times, with different values 1431 Put p = new Put(row); 1432 p.addColumn(FAMILY, QUALIFIER, 10, VALUE); 1433 table.put(p); 1434 p = new Put(row); 1435 p.addColumn(FAMILY, QUALIFIER, 11, ArrayUtils.add(VALUE, (byte) 2)); 1436 table.put(p); 1437 1438 p = new Put(row); 1439 p.addColumn(FAMILY, QUALIFIER, 12, ArrayUtils.add(VALUE, (byte) 3)); 1440 table.put(p); 1441 1442 p = new Put(row); 1443 p.addColumn(FAMILY, QUALIFIER, 13, ArrayUtils.add(VALUE, (byte) 4)); 1444 table.put(p); 1445 1446 int versions = 4; 1447 Scan s = new Scan(row); 1448 // get all the possible versions 1449 s.setMaxVersions(); 1450 s.setRaw(true); 1451 1452 try (ResultScanner scanner = table.getScanner(s)) { 1453 int count = 0; 1454 for (Result r : scanner) { 1455 assertEquals("Found an unexpected number of results for the row!", versions, 1456 r.listCells().size()); 1457 count++; 1458 } 1459 assertEquals("Found more than a single row when raw scanning the table with a single row!", 1460 1, count); 1461 } 1462 1463 // then if we decrease the number of versions, but keep the scan raw, we should see exactly 1464 // that number of versions 1465 versions = 2; 1466 s.setMaxVersions(versions); 1467 try (ResultScanner scanner = table.getScanner(s)) { 1468 int count = 0; 1469 for (Result r : scanner) { 1470 assertEquals("Found an unexpected number of results for the row!", versions, 1471 r.listCells().size()); 1472 count++; 1473 } 1474 assertEquals("Found more than a single row when raw scanning the table with a single row!", 1475 1, count); 1476 } 1477 1478 // finally, if we turn off raw scanning, but max out the number of versions, we should go back 1479 // to seeing just three 1480 versions = 3; 1481 s.setMaxVersions(versions); 1482 try (ResultScanner scanner = table.getScanner(s)) { 1483 int count = 0; 1484 for (Result r : scanner) { 1485 assertEquals("Found an unexpected number of results for the row!", versions, 1486 r.listCells().size()); 1487 count++; 1488 } 1489 assertEquals("Found more than a single row when raw scanning the table with a single row!", 1490 1, count); 1491 } 1492 1493 } 1494 TEST_UTIL.deleteTable(tableName); 1495 } 1496 1497 @Test 1498 public void testEmptyFilterList() throws Exception { 1499 // Test Initialization. 1500 final TableName tableName = name.getTableName(); 1501 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 1502 1503 // Insert one row each region 1504 Put put = new Put(Bytes.toBytes("row")); 1505 put.addColumn(FAMILY, QUALIFIER, VALUE); 1506 table.put(put); 1507 1508 List<Result> scanResults = new LinkedList<>(); 1509 Scan scan = new Scan(); 1510 scan.setFilter(new FilterList()); 1511 try (ResultScanner scanner = table.getScanner(scan)) { 1512 for (Result r : scanner) { 1513 scanResults.add(r); 1514 } 1515 } 1516 assertEquals(1, scanResults.size()); 1517 Get g = new Get(Bytes.toBytes("row")); 1518 g.setFilter(new FilterList()); 1519 Result getResult = table.get(g); 1520 Result scanResult = scanResults.get(0); 1521 assertEquals(scanResult.rawCells().length, getResult.rawCells().length); 1522 for (int i = 0; i != scanResult.rawCells().length; ++i) { 1523 Cell scanCell = scanResult.rawCells()[i]; 1524 Cell getCell = getResult.rawCells()[i]; 1525 assertEquals(0, Bytes.compareTo(CellUtil.cloneRow(scanCell), 1526 CellUtil.cloneRow(getCell))); 1527 assertEquals(0, Bytes.compareTo(CellUtil.cloneFamily(scanCell), 1528 CellUtil.cloneFamily(getCell))); 1529 assertEquals(0, Bytes.compareTo(CellUtil.cloneQualifier(scanCell), 1530 CellUtil.cloneQualifier(getCell))); 1531 assertEquals(0, Bytes.compareTo(CellUtil.cloneValue(scanCell), 1532 CellUtil.cloneValue(getCell))); 1533 } 1534 } 1535 } 1536 1537 @Test 1538 public void testSmallScan() throws Exception { 1539 // Test Initialization. 1540 final TableName tableName = name.getTableName(); 1541 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 1542 1543 // Insert one row each region 1544 int insertNum = 10; 1545 for (int i = 0; i < 10; i++) { 1546 Put put = new Put(Bytes.toBytes("row" + String.format("%03d", i))); 1547 put.addColumn(FAMILY, QUALIFIER, VALUE); 1548 table.put(put); 1549 } 1550 1551 // normal scan 1552 try (ResultScanner scanner = table.getScanner(new Scan())) { 1553 int count = 0; 1554 for (Result r : scanner) { 1555 assertFalse(r.isEmpty()); 1556 count++; 1557 } 1558 assertEquals(insertNum, count); 1559 } 1560 1561 // small scan 1562 Scan scan = new Scan(HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW); 1563 scan.setSmall(true); 1564 scan.setCaching(2); 1565 try (ResultScanner scanner = table.getScanner(scan)) { 1566 int count = 0; 1567 for (Result r : scanner) { 1568 assertFalse(r.isEmpty()); 1569 count++; 1570 } 1571 assertEquals(insertNum, count); 1572 } 1573 } 1574 } 1575 1576 @Test 1577 public void testSuperSimpleWithReverseScan() throws Exception { 1578 final TableName tableName = name.getTableName(); 1579 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) { 1580 Put put = new Put(Bytes.toBytes("0-b11111-0000000000000000000")); 1581 put.addColumn(FAMILY, QUALIFIER, VALUE); 1582 ht.put(put); 1583 put = new Put(Bytes.toBytes("0-b11111-0000000000000000002")); 1584 put.addColumn(FAMILY, QUALIFIER, VALUE); 1585 ht.put(put); 1586 put = new Put(Bytes.toBytes("0-b11111-0000000000000000004")); 1587 put.addColumn(FAMILY, QUALIFIER, VALUE); 1588 ht.put(put); 1589 put = new Put(Bytes.toBytes("0-b11111-0000000000000000006")); 1590 put.addColumn(FAMILY, QUALIFIER, VALUE); 1591 ht.put(put); 1592 put = new Put(Bytes.toBytes("0-b11111-0000000000000000008")); 1593 put.addColumn(FAMILY, QUALIFIER, VALUE); 1594 ht.put(put); 1595 put = new Put(Bytes.toBytes("0-b22222-0000000000000000001")); 1596 put.addColumn(FAMILY, QUALIFIER, VALUE); 1597 ht.put(put); 1598 put = new Put(Bytes.toBytes("0-b22222-0000000000000000003")); 1599 put.addColumn(FAMILY, QUALIFIER, VALUE); 1600 ht.put(put); 1601 put = new Put(Bytes.toBytes("0-b22222-0000000000000000005")); 1602 put.addColumn(FAMILY, QUALIFIER, VALUE); 1603 ht.put(put); 1604 put = new Put(Bytes.toBytes("0-b22222-0000000000000000007")); 1605 put.addColumn(FAMILY, QUALIFIER, VALUE); 1606 ht.put(put); 1607 put = new Put(Bytes.toBytes("0-b22222-0000000000000000009")); 1608 put.addColumn(FAMILY, QUALIFIER, VALUE); 1609 ht.put(put); 1610 Scan scan = new Scan(Bytes.toBytes("0-b11111-9223372036854775807"), 1611 Bytes.toBytes("0-b11111-0000000000000000000")); 1612 scan.setReversed(true); 1613 try (ResultScanner scanner = ht.getScanner(scan)) { 1614 Result result = scanner.next(); 1615 assertTrue(Bytes.equals(result.getRow(), 1616 Bytes.toBytes("0-b11111-0000000000000000008"))); 1617 } 1618 } 1619 } 1620 1621 @Test 1622 public void testFiltersWithReverseScan() throws Exception { 1623 final TableName tableName = name.getTableName(); 1624 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) { 1625 byte[][] ROWS = makeN(ROW, 10); 1626 byte[][] QUALIFIERS = {Bytes.toBytes("col0-<d2v1>-<d3v2>"), 1627 Bytes.toBytes("col1-<d2v1>-<d3v2>"), 1628 Bytes.toBytes("col2-<d2v1>-<d3v2>"), 1629 Bytes.toBytes("col3-<d2v1>-<d3v2>"), 1630 Bytes.toBytes("col4-<d2v1>-<d3v2>"), 1631 Bytes.toBytes("col5-<d2v1>-<d3v2>"), 1632 Bytes.toBytes("col6-<d2v1>-<d3v2>"), 1633 Bytes.toBytes("col7-<d2v1>-<d3v2>"), 1634 Bytes.toBytes("col8-<d2v1>-<d3v2>"), 1635 Bytes.toBytes("col9-<d2v1>-<d3v2>")}; 1636 for (int i = 0; i < 10; i++) { 1637 Put put = new Put(ROWS[i]); 1638 put.addColumn(FAMILY, QUALIFIERS[i], VALUE); 1639 ht.put(put); 1640 } 1641 Scan scan = new Scan(); 1642 scan.setReversed(true); 1643 scan.addFamily(FAMILY); 1644 Filter filter = new QualifierFilter(CompareOperator.EQUAL, 1645 new RegexStringComparator("col[1-5]")); 1646 scan.setFilter(filter); 1647 try (ResultScanner scanner = ht.getScanner(scan)) { 1648 int expectedIndex = 5; 1649 for (Result result : scanner) { 1650 assertEquals(1, result.size()); 1651 Cell c = result.rawCells()[0]; 1652 assertTrue(Bytes.equals(c.getRowArray(), c.getRowOffset(), c.getRowLength(), 1653 ROWS[expectedIndex], 0, ROWS[expectedIndex].length)); 1654 assertTrue(Bytes.equals(c.getQualifierArray(), c.getQualifierOffset(), 1655 c.getQualifierLength(), QUALIFIERS[expectedIndex], 0, 1656 QUALIFIERS[expectedIndex].length)); 1657 expectedIndex--; 1658 } 1659 assertEquals(0, expectedIndex); 1660 } 1661 } 1662 } 1663 1664 @Test 1665 public void testKeyOnlyFilterWithReverseScan() throws Exception { 1666 final TableName tableName = name.getTableName(); 1667 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) { 1668 byte[][] ROWS = makeN(ROW, 10); 1669 byte[][] QUALIFIERS = {Bytes.toBytes("col0-<d2v1>-<d3v2>"), 1670 Bytes.toBytes("col1-<d2v1>-<d3v2>"), 1671 Bytes.toBytes("col2-<d2v1>-<d3v2>"), 1672 Bytes.toBytes("col3-<d2v1>-<d3v2>"), 1673 Bytes.toBytes("col4-<d2v1>-<d3v2>"), 1674 Bytes.toBytes("col5-<d2v1>-<d3v2>"), 1675 Bytes.toBytes("col6-<d2v1>-<d3v2>"), 1676 Bytes.toBytes("col7-<d2v1>-<d3v2>"), 1677 Bytes.toBytes("col8-<d2v1>-<d3v2>"), 1678 Bytes.toBytes("col9-<d2v1>-<d3v2>")}; 1679 for (int i = 0; i < 10; i++) { 1680 Put put = new Put(ROWS[i]); 1681 put.addColumn(FAMILY, QUALIFIERS[i], VALUE); 1682 ht.put(put); 1683 } 1684 Scan scan = new Scan(); 1685 scan.setReversed(true); 1686 scan.addFamily(FAMILY); 1687 Filter filter = new KeyOnlyFilter(true); 1688 scan.setFilter(filter); 1689 try (ResultScanner ignored = ht.getScanner(scan)) { 1690 int count = 0; 1691 for (Result result : ht.getScanner(scan)) { 1692 assertEquals(1, result.size()); 1693 assertEquals(Bytes.SIZEOF_INT, result.rawCells()[0].getValueLength()); 1694 assertEquals(VALUE.length, Bytes.toInt(CellUtil.cloneValue(result.rawCells()[0]))); 1695 count++; 1696 } 1697 assertEquals(10, count); 1698 } 1699 } 1700 } 1701 1702 /** 1703 * Test simple table and non-existent row cases. 1704 */ 1705 @Test 1706 public void testSimpleMissingWithReverseScan() throws Exception { 1707 final TableName tableName = name.getTableName(); 1708 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) { 1709 byte[][] ROWS = makeN(ROW, 4); 1710 1711 // Try to get a row on an empty table 1712 Scan scan = new Scan(); 1713 scan.setReversed(true); 1714 Result result = getSingleScanResult(ht, scan); 1715 assertNullResult(result); 1716 1717 scan = new Scan(ROWS[0]); 1718 scan.setReversed(true); 1719 result = getSingleScanResult(ht, scan); 1720 assertNullResult(result); 1721 1722 scan = new Scan(ROWS[0], ROWS[1]); 1723 scan.setReversed(true); 1724 result = getSingleScanResult(ht, scan); 1725 assertNullResult(result); 1726 1727 scan = new Scan(); 1728 scan.setReversed(true); 1729 scan.addFamily(FAMILY); 1730 result = getSingleScanResult(ht, scan); 1731 assertNullResult(result); 1732 1733 scan = new Scan(); 1734 scan.setReversed(true); 1735 scan.addColumn(FAMILY, QUALIFIER); 1736 result = getSingleScanResult(ht, scan); 1737 assertNullResult(result); 1738 1739 // Insert a row 1740 1741 Put put = new Put(ROWS[2]); 1742 put.addColumn(FAMILY, QUALIFIER, VALUE); 1743 ht.put(put); 1744 1745 // Make sure we can scan the row 1746 scan = new Scan(); 1747 scan.setReversed(true); 1748 result = getSingleScanResult(ht, scan); 1749 assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE); 1750 1751 scan = new Scan(ROWS[3], ROWS[0]); 1752 scan.setReversed(true); 1753 result = getSingleScanResult(ht, scan); 1754 assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE); 1755 1756 scan = new Scan(ROWS[2], ROWS[1]); 1757 scan.setReversed(true); 1758 result = getSingleScanResult(ht, scan); 1759 assertSingleResult(result, ROWS[2], FAMILY, QUALIFIER, VALUE); 1760 1761 // Try to scan empty rows around it 1762 // Introduced MemStore#shouldSeekForReverseScan to fix the following 1763 scan = new Scan(ROWS[1]); 1764 scan.setReversed(true); 1765 result = getSingleScanResult(ht, scan); 1766 assertNullResult(result); 1767 } 1768 } 1769 1770 @Test 1771 public void testNullWithReverseScan() throws Exception { 1772 final TableName tableName = name.getTableName(); 1773 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) { 1774 // Null qualifier (should work) 1775 Put put = new Put(ROW); 1776 put.addColumn(FAMILY, null, VALUE); 1777 ht.put(put); 1778 scanTestNull(ht, ROW, FAMILY, VALUE, true); 1779 Delete delete = new Delete(ROW); 1780 delete.addColumns(FAMILY, null); 1781 ht.delete(delete); 1782 } 1783 1784 // Use a new table 1785 try (Table ht = 1786 TEST_UTIL.createTable(TableName.valueOf(name.getTableName().toString() + "2"), FAMILY)) { 1787 // Empty qualifier, byte[0] instead of null (should work) 1788 Put put = new Put(ROW); 1789 put.addColumn(FAMILY, HConstants.EMPTY_BYTE_ARRAY, VALUE); 1790 ht.put(put); 1791 scanTestNull(ht, ROW, FAMILY, VALUE, true); 1792 TEST_UTIL.flush(); 1793 scanTestNull(ht, ROW, FAMILY, VALUE, true); 1794 Delete delete = new Delete(ROW); 1795 delete.addColumns(FAMILY, HConstants.EMPTY_BYTE_ARRAY); 1796 ht.delete(delete); 1797 // Null value 1798 put = new Put(ROW); 1799 put.addColumn(FAMILY, QUALIFIER, null); 1800 ht.put(put); 1801 Scan scan = new Scan(); 1802 scan.setReversed(true); 1803 scan.addColumn(FAMILY, QUALIFIER); 1804 Result result = getSingleScanResult(ht, scan); 1805 assertSingleResult(result, ROW, FAMILY, QUALIFIER, null); 1806 } 1807 } 1808 1809 @Test 1810 @SuppressWarnings("checkstyle:MethodLength") 1811 public void testDeletesWithReverseScan() throws Exception { 1812 final TableName tableName = name.getTableName(); 1813 byte[][] ROWS = makeNAscii(ROW, 6); 1814 byte[][] FAMILIES = makeNAscii(FAMILY, 3); 1815 byte[][] VALUES = makeN(VALUE, 5); 1816 long[] ts = { 1000, 2000, 3000, 4000, 5000 }; 1817 try (Table ht = TEST_UTIL.createTable(tableName, FAMILIES, 3)) { 1818 1819 Put put = new Put(ROW); 1820 put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]); 1821 put.addColumn(FAMILIES[0], QUALIFIER, ts[1], VALUES[1]); 1822 ht.put(put); 1823 1824 Delete delete = new Delete(ROW); 1825 delete.addFamily(FAMILIES[0], ts[0]); 1826 ht.delete(delete); 1827 1828 Scan scan = new Scan(ROW); 1829 scan.setReversed(true); 1830 scan.addFamily(FAMILIES[0]); 1831 scan.setMaxVersions(Integer.MAX_VALUE); 1832 Result result = getSingleScanResult(ht, scan); 1833 assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1]}, 1834 new byte[][]{VALUES[1]}, 0, 0); 1835 1836 // Test delete latest version 1837 put = new Put(ROW); 1838 put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]); 1839 put.addColumn(FAMILIES[0], QUALIFIER, ts[2], VALUES[2]); 1840 put.addColumn(FAMILIES[0], QUALIFIER, ts[3], VALUES[3]); 1841 put.addColumn(FAMILIES[0], null, ts[4], VALUES[4]); 1842 put.addColumn(FAMILIES[0], null, ts[2], VALUES[2]); 1843 put.addColumn(FAMILIES[0], null, ts[3], VALUES[3]); 1844 ht.put(put); 1845 1846 delete = new Delete(ROW); 1847 delete.addColumn(FAMILIES[0], QUALIFIER); // ts[4] 1848 ht.delete(delete); 1849 1850 scan = new Scan(ROW); 1851 scan.setReversed(true); 1852 scan.addColumn(FAMILIES[0], QUALIFIER); 1853 scan.setMaxVersions(Integer.MAX_VALUE); 1854 result = getSingleScanResult(ht, scan); 1855 assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1], 1856 ts[2], ts[3]}, new byte[][]{VALUES[1], VALUES[2], VALUES[3]}, 0, 2); 1857 1858 // Test for HBASE-1847 1859 delete = new Delete(ROW); 1860 delete.addColumn(FAMILIES[0], null); 1861 ht.delete(delete); 1862 1863 // Cleanup null qualifier 1864 delete = new Delete(ROW); 1865 delete.addColumns(FAMILIES[0], null); 1866 ht.delete(delete); 1867 1868 // Expected client behavior might be that you can re-put deleted values 1869 // But alas, this is not to be. We can't put them back in either case. 1870 1871 put = new Put(ROW); 1872 put.addColumn(FAMILIES[0], QUALIFIER, ts[0], VALUES[0]); 1873 put.addColumn(FAMILIES[0], QUALIFIER, ts[4], VALUES[4]); 1874 ht.put(put); 1875 1876 // The Scanner returns the previous values, the expected-naive-unexpected 1877 // behavior 1878 1879 scan = new Scan(ROW); 1880 scan.setReversed(true); 1881 scan.addFamily(FAMILIES[0]); 1882 scan.setMaxVersions(Integer.MAX_VALUE); 1883 result = getSingleScanResult(ht, scan); 1884 assertNResult(result, ROW, FAMILIES[0], QUALIFIER, new long[]{ts[1], 1885 ts[2], ts[3]}, new byte[][]{VALUES[1], VALUES[2], VALUES[3]}, 0, 2); 1886 1887 // Test deleting an entire family from one row but not the other various 1888 // ways 1889 1890 put = new Put(ROWS[0]); 1891 put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]); 1892 put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]); 1893 put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]); 1894 put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]); 1895 ht.put(put); 1896 1897 put = new Put(ROWS[1]); 1898 put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]); 1899 put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]); 1900 put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]); 1901 put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]); 1902 ht.put(put); 1903 1904 put = new Put(ROWS[2]); 1905 put.addColumn(FAMILIES[1], QUALIFIER, ts[0], VALUES[0]); 1906 put.addColumn(FAMILIES[1], QUALIFIER, ts[1], VALUES[1]); 1907 put.addColumn(FAMILIES[2], QUALIFIER, ts[2], VALUES[2]); 1908 put.addColumn(FAMILIES[2], QUALIFIER, ts[3], VALUES[3]); 1909 ht.put(put); 1910 1911 delete = new Delete(ROWS[0]); 1912 delete.addFamily(FAMILIES[2]); 1913 ht.delete(delete); 1914 1915 delete = new Delete(ROWS[1]); 1916 delete.addColumns(FAMILIES[1], QUALIFIER); 1917 ht.delete(delete); 1918 1919 delete = new Delete(ROWS[2]); 1920 delete.addColumn(FAMILIES[1], QUALIFIER); 1921 delete.addColumn(FAMILIES[1], QUALIFIER); 1922 delete.addColumn(FAMILIES[2], QUALIFIER); 1923 ht.delete(delete); 1924 1925 scan = new Scan(ROWS[0]); 1926 scan.setReversed(true); 1927 scan.addFamily(FAMILIES[1]); 1928 scan.addFamily(FAMILIES[2]); 1929 scan.setMaxVersions(Integer.MAX_VALUE); 1930 result = getSingleScanResult(ht, scan); 1931 assertEquals("Expected 2 keys but received " + result.size(), 2, result.size()); 1932 assertNResult(result, ROWS[0], FAMILIES[1], QUALIFIER, new long[]{ts[0], 1933 ts[1]}, new byte[][]{VALUES[0], VALUES[1]}, 0, 1); 1934 1935 scan = new Scan(ROWS[1]); 1936 scan.setReversed(true); 1937 scan.addFamily(FAMILIES[1]); 1938 scan.addFamily(FAMILIES[2]); 1939 scan.setMaxVersions(Integer.MAX_VALUE); 1940 result = getSingleScanResult(ht, scan); 1941 assertEquals("Expected 2 keys but received " + result.size(), 2, result.size()); 1942 1943 scan = new Scan(ROWS[2]); 1944 scan.setReversed(true); 1945 scan.addFamily(FAMILIES[1]); 1946 scan.addFamily(FAMILIES[2]); 1947 scan.setMaxVersions(Integer.MAX_VALUE); 1948 result = getSingleScanResult(ht, scan); 1949 assertEquals(1, result.size()); 1950 assertNResult(result, ROWS[2], FAMILIES[2], QUALIFIER, 1951 new long[]{ts[2]}, new byte[][]{VALUES[2]}, 0, 0); 1952 1953 // Test if we delete the family first in one row (HBASE-1541) 1954 1955 delete = new Delete(ROWS[3]); 1956 delete.addFamily(FAMILIES[1]); 1957 ht.delete(delete); 1958 1959 put = new Put(ROWS[3]); 1960 put.addColumn(FAMILIES[2], QUALIFIER, VALUES[0]); 1961 ht.put(put); 1962 1963 put = new Put(ROWS[4]); 1964 put.addColumn(FAMILIES[1], QUALIFIER, VALUES[1]); 1965 put.addColumn(FAMILIES[2], QUALIFIER, VALUES[2]); 1966 ht.put(put); 1967 1968 scan = new Scan(ROWS[4]); 1969 scan.setReversed(true); 1970 scan.addFamily(FAMILIES[1]); 1971 scan.addFamily(FAMILIES[2]); 1972 scan.setMaxVersions(Integer.MAX_VALUE); 1973 ResultScanner scanner = ht.getScanner(scan); 1974 result = scanner.next(); 1975 assertEquals("Expected 2 keys but received " + result.size(), 2, result.size()); 1976 assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[4])); 1977 assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[1]), ROWS[4])); 1978 assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[1])); 1979 assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[1]), VALUES[2])); 1980 result = scanner.next(); 1981 assertEquals("Expected 1 key but received " + result.size(), 1, result.size()); 1982 assertTrue(Bytes.equals(CellUtil.cloneRow(result.rawCells()[0]), ROWS[3])); 1983 assertTrue(Bytes.equals(CellUtil.cloneValue(result.rawCells()[0]), VALUES[0])); 1984 scanner.close(); 1985 } 1986 } 1987 1988 /** 1989 * Tests reversed scan under multi regions 1990 */ 1991 @Test 1992 public void testReversedScanUnderMultiRegions() throws Exception { 1993 // Test Initialization. 1994 final TableName tableName = name.getTableName(); 1995 byte[] maxByteArray = ConnectionUtils.MAX_BYTE_ARRAY; 1996 byte[][] splitRows = new byte[][] { Bytes.toBytes("005"), 1997 Bytes.add(Bytes.toBytes("005"), Bytes.multiple(maxByteArray, 16)), 1998 Bytes.toBytes("006"), 1999 Bytes.add(Bytes.toBytes("006"), Bytes.multiple(maxByteArray, 8)), 2000 Bytes.toBytes("007"), 2001 Bytes.add(Bytes.toBytes("007"), Bytes.multiple(maxByteArray, 4)), 2002 Bytes.toBytes("008"), Bytes.multiple(maxByteArray, 2) }; 2003 try (Table table = TEST_UTIL.createTable(tableName, FAMILY, splitRows)) { 2004 TEST_UTIL.waitUntilAllRegionsAssigned(table.getName()); 2005 2006 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 2007 assertEquals(splitRows.length + 1, l.getAllRegionLocations().size()); 2008 } 2009 // Insert one row each region 2010 int insertNum = splitRows.length; 2011 for (byte[] splitRow : splitRows) { 2012 Put put = new Put(splitRow); 2013 put.addColumn(FAMILY, QUALIFIER, VALUE); 2014 table.put(put); 2015 } 2016 2017 // scan forward 2018 try (ResultScanner scanner = table.getScanner(new Scan())) { 2019 int count = 0; 2020 for (Result r : scanner) { 2021 assertFalse(r.isEmpty()); 2022 count++; 2023 } 2024 assertEquals(insertNum, count); 2025 } 2026 2027 // scan backward 2028 Scan scan = new Scan(); 2029 scan.setReversed(true); 2030 try (ResultScanner scanner = table.getScanner(scan)) { 2031 int count = 0; 2032 byte[] lastRow = null; 2033 for (Result r : scanner) { 2034 assertFalse(r.isEmpty()); 2035 count++; 2036 byte[] thisRow = r.getRow(); 2037 if (lastRow != null) { 2038 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2039 + ",this row=" + Bytes.toString(thisRow), 2040 Bytes.compareTo(thisRow, lastRow) < 0); 2041 } 2042 lastRow = thisRow; 2043 } 2044 assertEquals(insertNum, count); 2045 } 2046 } 2047 } 2048 2049 /** 2050 * Tests reversed scan under multi regions 2051 */ 2052 @Test 2053 public void testSmallReversedScanUnderMultiRegions() throws Exception { 2054 // Test Initialization. 2055 final TableName tableName = name.getTableName(); 2056 byte[][] splitRows = new byte[][]{ 2057 Bytes.toBytes("000"), Bytes.toBytes("002"), Bytes.toBytes("004"), 2058 Bytes.toBytes("006"), Bytes.toBytes("008"), Bytes.toBytes("010")}; 2059 try (Table table = TEST_UTIL.createTable(tableName, FAMILY, splitRows)) { 2060 TEST_UTIL.waitUntilAllRegionsAssigned(table.getName()); 2061 2062 try (RegionLocator l = TEST_UTIL.getConnection().getRegionLocator(tableName)) { 2063 assertEquals(splitRows.length + 1, l.getAllRegionLocations().size()); 2064 } 2065 for (byte[] splitRow : splitRows) { 2066 Put put = new Put(splitRow); 2067 put.addColumn(FAMILY, QUALIFIER, VALUE); 2068 table.put(put); 2069 2070 byte[] nextRow = Bytes.copy(splitRow); 2071 nextRow[nextRow.length - 1]++; 2072 2073 put = new Put(nextRow); 2074 put.addColumn(FAMILY, QUALIFIER, VALUE); 2075 table.put(put); 2076 } 2077 2078 // scan forward 2079 try (ResultScanner scanner = table.getScanner(new Scan())) { 2080 int count = 0; 2081 for (Result r : scanner) { 2082 assertTrue(!r.isEmpty()); 2083 count++; 2084 } 2085 assertEquals(12, count); 2086 } 2087 2088 reverseScanTest(table, false); 2089 reverseScanTest(table, true); 2090 } 2091 } 2092 2093 private void reverseScanTest(Table table, boolean small) throws IOException { 2094 // scan backward 2095 Scan scan = new Scan(); 2096 scan.setReversed(true); 2097 try (ResultScanner scanner = table.getScanner(scan)) { 2098 int count = 0; 2099 byte[] lastRow = null; 2100 for (Result r : scanner) { 2101 assertTrue(!r.isEmpty()); 2102 count++; 2103 byte[] thisRow = r.getRow(); 2104 if (lastRow != null) { 2105 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2106 + ",this row=" + Bytes.toString(thisRow), 2107 Bytes.compareTo(thisRow, lastRow) < 0); 2108 } 2109 lastRow = thisRow; 2110 } 2111 assertEquals(12, count); 2112 } 2113 2114 scan = new Scan(); 2115 scan.setSmall(small); 2116 scan.setReversed(true); 2117 scan.setStartRow(Bytes.toBytes("002")); 2118 try (ResultScanner scanner = table.getScanner(scan)) { 2119 int count = 0; 2120 byte[] lastRow = null; 2121 for (Result r : scanner) { 2122 assertTrue(!r.isEmpty()); 2123 count++; 2124 byte[] thisRow = r.getRow(); 2125 if (lastRow != null) { 2126 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2127 + ",this row=" + Bytes.toString(thisRow), 2128 Bytes.compareTo(thisRow, lastRow) < 0); 2129 } 2130 lastRow = thisRow; 2131 } 2132 assertEquals(3, count); // 000 001 002 2133 } 2134 2135 scan = new Scan(); 2136 scan.setSmall(small); 2137 scan.setReversed(true); 2138 scan.setStartRow(Bytes.toBytes("002")); 2139 scan.setStopRow(Bytes.toBytes("000")); 2140 try (ResultScanner scanner = table.getScanner(scan)) { 2141 int count = 0; 2142 byte[] lastRow = null; 2143 for (Result r : scanner) { 2144 assertFalse(r.isEmpty()); 2145 count++; 2146 byte[] thisRow = r.getRow(); 2147 if (lastRow != null) { 2148 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2149 + ",this row=" + Bytes.toString(thisRow), 2150 Bytes.compareTo(thisRow, lastRow) < 0); 2151 } 2152 lastRow = thisRow; 2153 } 2154 assertEquals(2, count); // 001 002 2155 } 2156 2157 scan = new Scan(); 2158 scan.setSmall(small); 2159 scan.setReversed(true); 2160 scan.setStartRow(Bytes.toBytes("001")); 2161 try (ResultScanner scanner = table.getScanner(scan)) { 2162 int count = 0; 2163 byte[] lastRow = null; 2164 for (Result r : scanner) { 2165 assertFalse(r.isEmpty()); 2166 count++; 2167 byte[] thisRow = r.getRow(); 2168 if (lastRow != null) { 2169 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2170 + ",this row=" + Bytes.toString(thisRow), 2171 Bytes.compareTo(thisRow, lastRow) < 0); 2172 } 2173 lastRow = thisRow; 2174 } 2175 assertEquals(2, count); // 000 001 2176 } 2177 2178 scan = new Scan(); 2179 scan.setSmall(small); 2180 scan.setReversed(true); 2181 scan.setStartRow(Bytes.toBytes("000")); 2182 try (ResultScanner scanner = table.getScanner(scan)) { 2183 int count = 0; 2184 byte[] lastRow = null; 2185 for (Result r : scanner) { 2186 assertFalse(r.isEmpty()); 2187 count++; 2188 byte[] thisRow = r.getRow(); 2189 if (lastRow != null) { 2190 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2191 + ",this row=" + Bytes.toString(thisRow), 2192 Bytes.compareTo(thisRow, lastRow) < 0); 2193 } 2194 lastRow = thisRow; 2195 } 2196 assertEquals(1, count); // 000 2197 } 2198 2199 scan = new Scan(); 2200 scan.setSmall(small); 2201 scan.setReversed(true); 2202 scan.setStartRow(Bytes.toBytes("006")); 2203 scan.setStopRow(Bytes.toBytes("002")); 2204 try (ResultScanner scanner = table.getScanner(scan)) { 2205 int count = 0; 2206 byte[] lastRow = null; 2207 for (Result r : scanner) { 2208 assertFalse(r.isEmpty()); 2209 count++; 2210 byte[] thisRow = r.getRow(); 2211 if (lastRow != null) { 2212 assertTrue("Error scan order, last row= " + Bytes.toString(lastRow) 2213 + ",this row=" + Bytes.toString(thisRow), 2214 Bytes.compareTo(thisRow, lastRow) < 0); 2215 } 2216 lastRow = thisRow; 2217 } 2218 assertEquals(4, count); // 003 004 005 006 2219 } 2220 } 2221 2222 @Test 2223 public void testFilterAllRecords() throws IOException { 2224 Scan scan = new Scan(); 2225 scan.setBatch(1); 2226 scan.setCaching(1); 2227 // Filter out any records 2228 scan.setFilter(new FilterList(new FirstKeyOnlyFilter(), new InclusiveStopFilter(new byte[0]))); 2229 try (Table table = TEST_UTIL.getConnection().getTable(TableName.META_TABLE_NAME)) { 2230 try (ResultScanner s = table.getScanner(scan)) { 2231 assertNull(s.next()); 2232 } 2233 } 2234 } 2235 2236 @Test 2237 public void testCellSizeLimit() throws IOException { 2238 final TableName tableName = name.getTableName(); 2239 TableDescriptorBuilder.ModifyableTableDescriptor tableDescriptor = 2240 new TableDescriptorBuilder.ModifyableTableDescriptor(tableName) 2241 .setValue(HRegion.HBASE_MAX_CELL_SIZE_KEY, Integer.toString(10 * 1024)); 2242 ColumnFamilyDescriptor familyDescriptor = 2243 new ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor(FAMILY); 2244 2245 tableDescriptor.setColumnFamily(familyDescriptor); 2246 try (Admin admin = TEST_UTIL.getAdmin()) { 2247 admin.createTable(tableDescriptor); 2248 } 2249 // Will succeed 2250 try (Table t = TEST_UTIL.getConnection().getTable(tableName)) { 2251 t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, Bytes.toBytes(0L))); 2252 t.increment(new Increment(ROW).addColumn(FAMILY, QUALIFIER, 1L)); 2253 } 2254 // Will succeed 2255 try (Table t = TEST_UTIL.getConnection().getTable(tableName)) { 2256 t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, new byte[9*1024])); 2257 } 2258 // Will fail 2259 try (Table t = TEST_UTIL.getConnection().getTable(tableName)) { 2260 try { 2261 t.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, new byte[10 * 1024])); 2262 fail("Oversize cell failed to trigger exception"); 2263 } catch (IOException e) { 2264 // expected 2265 } 2266 try { 2267 t.append(new Append(ROW).addColumn(FAMILY, QUALIFIER, new byte[2 * 1024])); 2268 fail("Oversize cell failed to trigger exception"); 2269 } catch (IOException e) { 2270 // expected 2271 } 2272 } 2273 } 2274 2275 @Test 2276 public void testCellSizeNoLimit() throws IOException { 2277 final TableName tableName = name.getTableName(); 2278 ColumnFamilyDescriptor familyDescriptor = 2279 new ColumnFamilyDescriptorBuilder.ModifyableColumnFamilyDescriptor(FAMILY); 2280 TableDescriptorBuilder.ModifyableTableDescriptor tableDescriptor = 2281 new TableDescriptorBuilder.ModifyableTableDescriptor(tableName) 2282 .setValue(HRegion.HBASE_MAX_CELL_SIZE_KEY, Integer.toString(0)); 2283 tableDescriptor.setColumnFamily(familyDescriptor); 2284 2285 try (Admin admin = TEST_UTIL.getAdmin()) { 2286 admin.createTable(tableDescriptor); 2287 } 2288 2289 // Will succeed 2290 try (Table ht = TEST_UTIL.getConnection().getTable(tableName)) { 2291 ht.put(new Put(ROW).addColumn(FAMILY, QUALIFIER, new byte[HRegion.DEFAULT_MAX_CELL_SIZE - 2292 1024])); 2293 ht.append(new Append(ROW).addColumn(FAMILY, QUALIFIER, new byte[1024 + 1])); 2294 } 2295 } 2296 2297 @Test 2298 public void testDeleteSpecifiedVersionOfSpecifiedColumn() throws Exception { 2299 final TableName tableName = name.getTableName(); 2300 2301 byte[][] VALUES = makeN(VALUE, 5); 2302 long[] ts = {1000, 2000, 3000, 4000, 5000}; 2303 2304 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 5)) { 2305 2306 Put put = new Put(ROW); 2307 // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER 2308 for (int t = 0; t < 4; t++) { 2309 put.addColumn(FAMILY, QUALIFIER, ts[t], VALUES[t]); 2310 } 2311 ht.put(put); 2312 2313 Delete delete = new Delete(ROW); 2314 // Delete version 3000 of column FAMILY:QUALIFIER 2315 delete.addColumn(FAMILY, QUALIFIER, ts[2]); 2316 ht.delete(delete); 2317 2318 Get get = new Get(ROW); 2319 get.addColumn(FAMILY, QUALIFIER); 2320 get.readVersions(Integer.MAX_VALUE); 2321 Result result = ht.get(get); 2322 // verify version 1000,2000,4000 remains for column FAMILY:QUALIFIER 2323 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[3]}, new byte[][]{ 2324 VALUES[0], VALUES[1], VALUES[3]}, 0, 2); 2325 2326 delete = new Delete(ROW); 2327 // Delete a version 5000 of column FAMILY:QUALIFIER which didn't exist 2328 delete.addColumn(FAMILY, QUALIFIER, ts[4]); 2329 ht.delete(delete); 2330 2331 get = new Get(ROW); 2332 get.addColumn(FAMILY, QUALIFIER); 2333 get.readVersions(Integer.MAX_VALUE); 2334 result = ht.get(get); 2335 // verify version 1000,2000,4000 remains for column FAMILY:QUALIFIER 2336 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[3]}, new byte[][]{ 2337 VALUES[0], VALUES[1], VALUES[3]}, 0, 2); 2338 } 2339 } 2340 2341 @Test 2342 public void testDeleteLatestVersionOfSpecifiedColumn() throws Exception { 2343 final TableName tableName = name.getTableName(); 2344 byte[][] VALUES = makeN(VALUE, 5); 2345 long[] ts = {1000, 2000, 3000, 4000, 5000}; 2346 try (Table ht = TEST_UTIL.createTable(tableName, FAMILY, 5)) { 2347 Put put = new Put(ROW); 2348 // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER 2349 for (int t = 0; t < 4; t++) { 2350 put.addColumn(FAMILY, QUALIFIER, ts[t], VALUES[t]); 2351 } 2352 ht.put(put); 2353 2354 Delete delete = new Delete(ROW); 2355 // Delete latest version of column FAMILY:QUALIFIER 2356 delete.addColumn(FAMILY, QUALIFIER); 2357 ht.delete(delete); 2358 2359 Get get = new Get(ROW); 2360 get.addColumn(FAMILY, QUALIFIER); 2361 get.readVersions(Integer.MAX_VALUE); 2362 Result result = ht.get(get); 2363 // verify version 1000,2000,3000 remains for column FAMILY:QUALIFIER 2364 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[1], ts[2]}, new byte[][]{ 2365 VALUES[0], VALUES[1], VALUES[2]}, 0, 2); 2366 2367 delete = new Delete(ROW); 2368 // Delete two latest version of column FAMILY:QUALIFIER 2369 delete.addColumn(FAMILY, QUALIFIER); 2370 delete.addColumn(FAMILY, QUALIFIER); 2371 ht.delete(delete); 2372 2373 get = new Get(ROW); 2374 get.addColumn(FAMILY, QUALIFIER); 2375 get.readVersions(Integer.MAX_VALUE); 2376 result = ht.get(get); 2377 // verify version 1000 remains for column FAMILY:QUALIFIER 2378 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0]}, new byte[][]{VALUES[0]}, 2379 0, 0); 2380 2381 put = new Put(ROW); 2382 // Put a version 5000 of column FAMILY:QUALIFIER 2383 put.addColumn(FAMILY, QUALIFIER, ts[4], VALUES[4]); 2384 ht.put(put); 2385 2386 get = new Get(ROW); 2387 get.addColumn(FAMILY, QUALIFIER); 2388 get.readVersions(Integer.MAX_VALUE); 2389 result = ht.get(get); 2390 // verify version 1000,5000 remains for column FAMILY:QUALIFIER 2391 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[0], ts[4]}, new byte[][]{ 2392 VALUES[0], VALUES[4]}, 0, 1); 2393 } 2394 } 2395 2396 /** 2397 * Test for HBASE-17125 2398 */ 2399 @Test 2400 public void testReadWithFilter() throws Exception { 2401 final TableName tableName = name.getTableName(); 2402 try (Table table = TEST_UTIL.createTable(tableName, FAMILY, 3)) { 2403 2404 byte[] VALUEA = Bytes.toBytes("value-a"); 2405 byte[] VALUEB = Bytes.toBytes("value-b"); 2406 long[] ts = {1000, 2000, 3000, 4000}; 2407 2408 Put put = new Put(ROW); 2409 // Put version 1000,2000,3000,4000 of column FAMILY:QUALIFIER 2410 for (int t = 0; t <= 3; t++) { 2411 if (t <= 1) { 2412 put.addColumn(FAMILY, QUALIFIER, ts[t], VALUEA); 2413 } else { 2414 put.addColumn(FAMILY, QUALIFIER, ts[t], VALUEB); 2415 } 2416 } 2417 table.put(put); 2418 2419 Scan scan = 2420 new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL, 2421 new SubstringComparator("value-a"))) 2422 .setMaxVersions(3); 2423 ResultScanner scanner = table.getScanner(scan); 2424 Result result = scanner.next(); 2425 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2426 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2427 0); 2428 2429 Get get = 2430 new Get(ROW) 2431 .setFilter(new ValueFilter(CompareOperator.EQUAL, 2432 new SubstringComparator("value-a"))) 2433 .readVersions(3); 2434 result = table.get(get); 2435 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2436 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2437 0); 2438 2439 // Test with max versions 1, it should still read ts[1] 2440 scan = 2441 new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL, 2442 new SubstringComparator("value-a"))) 2443 .setMaxVersions(1); 2444 scanner = table.getScanner(scan); 2445 result = scanner.next(); 2446 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2447 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2448 0); 2449 2450 // Test with max versions 1, it should still read ts[1] 2451 get = 2452 new Get(ROW) 2453 .setFilter(new ValueFilter(CompareOperator.EQUAL, 2454 new SubstringComparator("value-a"))) 2455 .readVersions(1); 2456 result = table.get(get); 2457 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2458 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2459 0); 2460 2461 // Test with max versions 5, it should still read ts[1] 2462 scan = 2463 new Scan().setFilter(new ValueFilter(CompareOperator.EQUAL, 2464 new SubstringComparator("value-a"))) 2465 .setMaxVersions(5); 2466 scanner = table.getScanner(scan); 2467 result = scanner.next(); 2468 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2469 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2470 0); 2471 2472 // Test with max versions 5, it should still read ts[1] 2473 get = 2474 new Get(ROW) 2475 .setFilter(new ValueFilter(CompareOperator.EQUAL, 2476 new SubstringComparator("value-a"))) 2477 .readVersions(5); 2478 result = table.get(get); 2479 // ts[0] has gone from user view. Only read ts[2] which value is less or equal to 3 2480 assertNResult(result, ROW, FAMILY, QUALIFIER, new long[]{ts[1]}, new byte[][]{VALUEA}, 0, 2481 0); 2482 } 2483 } 2484 2485 @Test 2486 public void testCellUtilTypeMethods() throws IOException { 2487 final TableName tableName = name.getTableName(); 2488 try (Table table = TEST_UTIL.createTable(tableName, FAMILY)) { 2489 2490 final byte[] row = Bytes.toBytes("p"); 2491 Put p = new Put(row); 2492 p.addColumn(FAMILY, QUALIFIER, VALUE); 2493 table.put(p); 2494 2495 try (ResultScanner scanner = table.getScanner(new Scan())) { 2496 Result result = scanner.next(); 2497 assertNotNull(result); 2498 CellScanner cs = result.cellScanner(); 2499 assertTrue(cs.advance()); 2500 Cell c = cs.current(); 2501 assertTrue(CellUtil.isPut(c)); 2502 assertFalse(CellUtil.isDelete(c)); 2503 assertFalse(cs.advance()); 2504 assertNull(scanner.next()); 2505 } 2506 2507 Delete d = new Delete(row); 2508 d.addColumn(FAMILY, QUALIFIER); 2509 table.delete(d); 2510 2511 Scan scan = new Scan(); 2512 scan.setRaw(true); 2513 try (ResultScanner scanner = table.getScanner(scan)) { 2514 Result result = scanner.next(); 2515 assertNotNull(result); 2516 CellScanner cs = result.cellScanner(); 2517 assertTrue(cs.advance()); 2518 2519 // First cell should be the delete (masking the Put) 2520 Cell c = cs.current(); 2521 assertTrue("Cell should be a Delete: " + c, CellUtil.isDelete(c)); 2522 assertFalse("Cell should not be a Put: " + c, CellUtil.isPut(c)); 2523 2524 // Second cell should be the original Put 2525 assertTrue(cs.advance()); 2526 c = cs.current(); 2527 assertFalse("Cell should not be a Delete: " + c, CellUtil.isDelete(c)); 2528 assertTrue("Cell should be a Put: " + c, CellUtil.isPut(c)); 2529 2530 // No more cells in this row 2531 assertFalse(cs.advance()); 2532 2533 // No more results in this scan 2534 assertNull(scanner.next()); 2535 } 2536 } 2537 } 2538 2539 @Test(expected = DoNotRetryIOException.class) 2540 public void testCreateTableWithZeroRegionReplicas() throws Exception { 2541 TableName tableName = name.getTableName(); 2542 TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName) 2543 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf"))) 2544 .setRegionReplication(0) 2545 .build(); 2546 2547 TEST_UTIL.getAdmin().createTable(desc); 2548 } 2549 2550 @Test(expected = DoNotRetryIOException.class) 2551 public void testModifyTableWithZeroRegionReplicas() throws Exception { 2552 TableName tableName = name.getTableName(); 2553 TableDescriptor desc = TableDescriptorBuilder.newBuilder(tableName) 2554 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(Bytes.toBytes("cf"))) 2555 .build(); 2556 2557 TEST_UTIL.getAdmin().createTable(desc); 2558 TableDescriptor newDesc = TableDescriptorBuilder.newBuilder(desc) 2559 .setRegionReplication(0) 2560 .build(); 2561 2562 TEST_UTIL.getAdmin().modifyTable(newDesc); 2563 } 2564 2565 @Test(timeout = 60000) 2566 public void testModifyTableWithMemstoreData() throws Exception { 2567 TableName tableName = name.getTableName(); 2568 createTableAndValidateTableSchemaModification(tableName, true); 2569 } 2570 2571 @Test(timeout = 60000) 2572 public void testDeleteCFWithMemstoreData() throws Exception { 2573 TableName tableName = name.getTableName(); 2574 createTableAndValidateTableSchemaModification(tableName, false); 2575 } 2576 2577 /** 2578 * Create table and validate online schema modification 2579 * @param tableName Table name 2580 * @param modifyTable Modify table if true otherwise delete column family 2581 * @throws IOException in case of failures 2582 */ 2583 private void createTableAndValidateTableSchemaModification(TableName tableName, 2584 boolean modifyTable) throws Exception { 2585 Admin admin = TEST_UTIL.getAdmin(); 2586 // Create table with two Cfs 2587 byte[] cf1 = Bytes.toBytes("cf1"); 2588 byte[] cf2 = Bytes.toBytes("cf2"); 2589 TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tableName) 2590 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf1)) 2591 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(cf2)).build(); 2592 admin.createTable(tableDesc); 2593 2594 Table t = TEST_UTIL.getConnection().getTable(tableName); 2595 // Insert few records and flush the table 2596 t.put(new Put(ROW).addColumn(cf1, QUALIFIER, Bytes.toBytes("val1"))); 2597 t.put(new Put(ROW).addColumn(cf2, QUALIFIER, Bytes.toBytes("val2"))); 2598 admin.flush(tableName); 2599 Path tableDir = CommonFSUtils.getTableDir(TEST_UTIL.getDefaultRootDirPath(), tableName); 2600 List<Path> regionDirs = FSUtils.getRegionDirs(TEST_UTIL.getTestFileSystem(), tableDir); 2601 assertEquals(1, regionDirs.size()); 2602 List<Path> familyDirs = FSUtils.getFamilyDirs(TEST_UTIL.getTestFileSystem(), regionDirs.get(0)); 2603 assertEquals(2, familyDirs.size()); 2604 2605 // Insert record but dont flush the table 2606 t.put(new Put(ROW).addColumn(cf1, QUALIFIER, Bytes.toBytes("val2"))); 2607 t.put(new Put(ROW).addColumn(cf2, QUALIFIER, Bytes.toBytes("val2"))); 2608 2609 if (modifyTable) { 2610 tableDesc = TableDescriptorBuilder.newBuilder(tableDesc).removeColumnFamily(cf2).build(); 2611 admin.modifyTable(tableDesc); 2612 } else { 2613 admin.deleteColumnFamily(tableName, cf2); 2614 } 2615 // After table modification or delete family there should be only one CF in FS 2616 familyDirs = FSUtils.getFamilyDirs(TEST_UTIL.getTestFileSystem(), regionDirs.get(0)); 2617 assertEquals("CF dir count should be 1, but was " + familyDirs.size(), 1, familyDirs.size()); 2618 } 2619}