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.regionserver; 019 020import static org.apache.hadoop.hbase.HBaseTestingUtility.COLUMNS; 021import static org.apache.hadoop.hbase.HBaseTestingUtility.fam1; 022import static org.apache.hadoop.hbase.HBaseTestingUtility.fam2; 023import static org.apache.hadoop.hbase.HBaseTestingUtility.fam3; 024import static org.junit.Assert.assertArrayEquals; 025import static org.junit.Assert.assertEquals; 026import static org.junit.Assert.assertFalse; 027import static org.junit.Assert.assertNotNull; 028import static org.junit.Assert.assertNull; 029import static org.junit.Assert.assertTrue; 030import static org.junit.Assert.fail; 031import static org.mockito.ArgumentMatchers.any; 032import static org.mockito.ArgumentMatchers.anyBoolean; 033import static org.mockito.ArgumentMatchers.anyLong; 034import static org.mockito.Mockito.doThrow; 035import static org.mockito.Mockito.mock; 036import static org.mockito.Mockito.never; 037import static org.mockito.Mockito.spy; 038import static org.mockito.Mockito.times; 039import static org.mockito.Mockito.verify; 040import static org.mockito.Mockito.when; 041 042import java.io.IOException; 043import java.io.InterruptedIOException; 044import java.math.BigDecimal; 045import java.nio.charset.StandardCharsets; 046import java.security.PrivilegedExceptionAction; 047import java.util.ArrayList; 048import java.util.Arrays; 049import java.util.Collection; 050import java.util.List; 051import java.util.Map; 052import java.util.NavigableMap; 053import java.util.Objects; 054import java.util.TreeMap; 055import java.util.UUID; 056import java.util.concurrent.Callable; 057import java.util.concurrent.CountDownLatch; 058import java.util.concurrent.ExecutorService; 059import java.util.concurrent.Executors; 060import java.util.concurrent.Future; 061import java.util.concurrent.TimeUnit; 062import java.util.concurrent.atomic.AtomicBoolean; 063import java.util.concurrent.atomic.AtomicInteger; 064import java.util.concurrent.atomic.AtomicReference; 065import org.apache.commons.lang3.RandomStringUtils; 066import org.apache.hadoop.conf.Configuration; 067import org.apache.hadoop.fs.FSDataOutputStream; 068import org.apache.hadoop.fs.FileStatus; 069import org.apache.hadoop.fs.FileSystem; 070import org.apache.hadoop.fs.Path; 071import org.apache.hadoop.hbase.ArrayBackedTag; 072import org.apache.hadoop.hbase.Cell; 073import org.apache.hadoop.hbase.Cell.Type; 074import org.apache.hadoop.hbase.CellBuilderFactory; 075import org.apache.hadoop.hbase.CellBuilderType; 076import org.apache.hadoop.hbase.CellUtil; 077import org.apache.hadoop.hbase.CompareOperator; 078import org.apache.hadoop.hbase.CompatibilitySingletonFactory; 079import org.apache.hadoop.hbase.DroppedSnapshotException; 080import org.apache.hadoop.hbase.HBaseClassTestRule; 081import org.apache.hadoop.hbase.HBaseConfiguration; 082import org.apache.hadoop.hbase.HBaseTestingUtility; 083import org.apache.hadoop.hbase.HColumnDescriptor; 084import org.apache.hadoop.hbase.HConstants; 085import org.apache.hadoop.hbase.HConstants.OperationStatusCode; 086import org.apache.hadoop.hbase.HDFSBlocksDistribution; 087import org.apache.hadoop.hbase.HRegionInfo; 088import org.apache.hadoop.hbase.HTableDescriptor; 089import org.apache.hadoop.hbase.KeyValue; 090import org.apache.hadoop.hbase.KeyValueUtil; 091import org.apache.hadoop.hbase.MiniHBaseCluster; 092import org.apache.hadoop.hbase.MultithreadedTestUtil; 093import org.apache.hadoop.hbase.MultithreadedTestUtil.RepeatingTestThread; 094import org.apache.hadoop.hbase.MultithreadedTestUtil.TestThread; 095import org.apache.hadoop.hbase.NotServingRegionException; 096import org.apache.hadoop.hbase.PrivateCellUtil; 097import org.apache.hadoop.hbase.RegionTooBusyException; 098import org.apache.hadoop.hbase.ServerName; 099import org.apache.hadoop.hbase.TableName; 100import org.apache.hadoop.hbase.TagType; 101import org.apache.hadoop.hbase.Waiter; 102import org.apache.hadoop.hbase.client.Append; 103import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 104import org.apache.hadoop.hbase.client.Delete; 105import org.apache.hadoop.hbase.client.Durability; 106import org.apache.hadoop.hbase.client.Get; 107import org.apache.hadoop.hbase.client.Increment; 108import org.apache.hadoop.hbase.client.Mutation; 109import org.apache.hadoop.hbase.client.Put; 110import org.apache.hadoop.hbase.client.RegionInfo; 111import org.apache.hadoop.hbase.client.RegionInfoBuilder; 112import org.apache.hadoop.hbase.client.Result; 113import org.apache.hadoop.hbase.client.RowMutations; 114import org.apache.hadoop.hbase.client.Scan; 115import org.apache.hadoop.hbase.client.Table; 116import org.apache.hadoop.hbase.client.TableDescriptor; 117import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 118import org.apache.hadoop.hbase.exceptions.FailedSanityCheckException; 119import org.apache.hadoop.hbase.filter.BigDecimalComparator; 120import org.apache.hadoop.hbase.filter.BinaryComparator; 121import org.apache.hadoop.hbase.filter.ColumnCountGetFilter; 122import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; 123import org.apache.hadoop.hbase.filter.Filter; 124import org.apache.hadoop.hbase.filter.FilterBase; 125import org.apache.hadoop.hbase.filter.FilterList; 126import org.apache.hadoop.hbase.filter.NullComparator; 127import org.apache.hadoop.hbase.filter.PrefixFilter; 128import org.apache.hadoop.hbase.filter.SingleColumnValueExcludeFilter; 129import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; 130import org.apache.hadoop.hbase.filter.SubstringComparator; 131import org.apache.hadoop.hbase.filter.ValueFilter; 132import org.apache.hadoop.hbase.io.hfile.HFile; 133import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler; 134import org.apache.hadoop.hbase.monitoring.MonitoredTask; 135import org.apache.hadoop.hbase.monitoring.TaskMonitor; 136import org.apache.hadoop.hbase.regionserver.HRegion.MutationBatchOperation; 137import org.apache.hadoop.hbase.regionserver.HRegion.RegionScannerImpl; 138import org.apache.hadoop.hbase.regionserver.Region.RowLock; 139import org.apache.hadoop.hbase.regionserver.TestHStore.FaultyFileSystem; 140import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequestImpl; 141import org.apache.hadoop.hbase.regionserver.wal.FSHLog; 142import org.apache.hadoop.hbase.regionserver.wal.MetricsWALSource; 143import org.apache.hadoop.hbase.regionserver.wal.WALUtil; 144import org.apache.hadoop.hbase.replication.regionserver.ReplicationObserver; 145import org.apache.hadoop.hbase.security.User; 146import org.apache.hadoop.hbase.test.MetricsAssertHelper; 147import org.apache.hadoop.hbase.testclassification.LargeTests; 148import org.apache.hadoop.hbase.testclassification.VerySlowRegionServerTests; 149import org.apache.hadoop.hbase.util.Bytes; 150import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 151import org.apache.hadoop.hbase.util.EnvironmentEdgeManagerTestHelper; 152import org.apache.hadoop.hbase.util.FSUtils; 153import org.apache.hadoop.hbase.util.IncrementingEnvironmentEdge; 154import org.apache.hadoop.hbase.util.ManualEnvironmentEdge; 155import org.apache.hadoop.hbase.util.Threads; 156import org.apache.hadoop.hbase.wal.AbstractFSWALProvider; 157import org.apache.hadoop.hbase.wal.FaultyFSLog; 158import org.apache.hadoop.hbase.wal.WAL; 159import org.apache.hadoop.hbase.wal.WALEdit; 160import org.apache.hadoop.hbase.wal.WALFactory; 161import org.apache.hadoop.hbase.wal.WALKeyImpl; 162import org.apache.hadoop.hbase.wal.WALProvider; 163import org.apache.hadoop.hbase.wal.WALProvider.Writer; 164import org.apache.hadoop.hbase.wal.WALSplitter; 165import org.junit.After; 166import org.junit.Assert; 167import org.junit.Before; 168import org.junit.ClassRule; 169import org.junit.Rule; 170import org.junit.Test; 171import org.junit.experimental.categories.Category; 172import org.junit.rules.ExpectedException; 173import org.junit.rules.TestName; 174import org.mockito.ArgumentCaptor; 175import org.mockito.ArgumentMatcher; 176import org.mockito.Mockito; 177import org.mockito.invocation.InvocationOnMock; 178import org.mockito.stubbing.Answer; 179import org.slf4j.Logger; 180import org.slf4j.LoggerFactory; 181 182import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 183import org.apache.hbase.thirdparty.com.google.protobuf.ByteString; 184 185import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 186import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.CompactionDescriptor; 187import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor; 188import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor.FlushAction; 189import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor.StoreFlushDescriptor; 190import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor; 191import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.StoreDescriptor; 192 193/** 194 * Basic stand-alone testing of HRegion. No clusters! 195 * 196 * A lot of the meta information for an HRegion now lives inside other HRegions 197 * or in the HBaseMaster, so only basic testing is possible. 198 */ 199@Category({VerySlowRegionServerTests.class, LargeTests.class}) 200@SuppressWarnings("deprecation") 201public class TestHRegion { 202 203 @ClassRule 204 public static final HBaseClassTestRule CLASS_RULE = 205 HBaseClassTestRule.forClass(TestHRegion.class); 206 207 // Do not spin up clusters in here. If you need to spin up a cluster, do it 208 // over in TestHRegionOnCluster. 209 private static final Logger LOG = LoggerFactory.getLogger(TestHRegion.class); 210 @Rule 211 public TestName name = new TestName(); 212 @Rule public final ExpectedException thrown = ExpectedException.none(); 213 214 private static final String COLUMN_FAMILY = "MyCF"; 215 private static final byte [] COLUMN_FAMILY_BYTES = Bytes.toBytes(COLUMN_FAMILY); 216 217 HRegion region = null; 218 // Do not run unit tests in parallel (? Why not? It don't work? Why not? St.Ack) 219 protected static HBaseTestingUtility TEST_UTIL; 220 public static Configuration CONF ; 221 private String dir; 222 private static FileSystem FILESYSTEM; 223 private final int MAX_VERSIONS = 2; 224 225 // Test names 226 protected TableName tableName; 227 protected String method; 228 protected final byte[] qual = Bytes.toBytes("qual"); 229 protected final byte[] qual1 = Bytes.toBytes("qual1"); 230 protected final byte[] qual2 = Bytes.toBytes("qual2"); 231 protected final byte[] qual3 = Bytes.toBytes("qual3"); 232 protected final byte[] value = Bytes.toBytes("value"); 233 protected final byte[] value1 = Bytes.toBytes("value1"); 234 protected final byte[] value2 = Bytes.toBytes("value2"); 235 protected final byte[] row = Bytes.toBytes("rowA"); 236 protected final byte[] row2 = Bytes.toBytes("rowB"); 237 238 protected final MetricsAssertHelper metricsAssertHelper = CompatibilitySingletonFactory 239 .getInstance(MetricsAssertHelper.class); 240 241 @Before 242 public void setup() throws IOException { 243 TEST_UTIL = HBaseTestingUtility.createLocalHTU(); 244 FILESYSTEM = TEST_UTIL.getTestFileSystem(); 245 CONF = TEST_UTIL.getConfiguration(); 246 dir = TEST_UTIL.getDataTestDir("TestHRegion").toString(); 247 method = name.getMethodName(); 248 tableName = TableName.valueOf(method); 249 CONF.set(CompactingMemStore.IN_MEMORY_FLUSH_THRESHOLD_FACTOR_KEY, String.valueOf(0.09)); 250 } 251 252 @After 253 public void tearDown() throws Exception { 254 EnvironmentEdgeManagerTestHelper.reset(); 255 LOG.info("Cleaning test directory: " + TEST_UTIL.getDataTestDir()); 256 TEST_UTIL.cleanupTestDir(); 257 } 258 259 /** 260 * Test that I can use the max flushed sequence id after the close. 261 * @throws IOException 262 */ 263 @Test 264 public void testSequenceId() throws IOException { 265 HRegion region = initHRegion(tableName, method, CONF, COLUMN_FAMILY_BYTES); 266 assertEquals(HConstants.NO_SEQNUM, region.getMaxFlushedSeqId()); 267 // Weird. This returns 0 if no store files or no edits. Afraid to change it. 268 assertEquals(0, (long)region.getMaxStoreSeqId().get(COLUMN_FAMILY_BYTES)); 269 region.close(); 270 assertEquals(HConstants.NO_SEQNUM, region.getMaxFlushedSeqId()); 271 assertEquals(0, (long)region.getMaxStoreSeqId().get(COLUMN_FAMILY_BYTES)); 272 // Open region again. 273 region = initHRegion(tableName, method, CONF, COLUMN_FAMILY_BYTES); 274 byte [] value = Bytes.toBytes(method); 275 // Make a random put against our cf. 276 Put put = new Put(value); 277 put.addColumn(COLUMN_FAMILY_BYTES, null, value); 278 region.put(put); 279 // No flush yet so init numbers should still be in place. 280 assertEquals(HConstants.NO_SEQNUM, region.getMaxFlushedSeqId()); 281 assertEquals(0, (long)region.getMaxStoreSeqId().get(COLUMN_FAMILY_BYTES)); 282 region.flush(true); 283 long max = region.getMaxFlushedSeqId(); 284 region.close(); 285 assertEquals(max, region.getMaxFlushedSeqId()); 286 } 287 288 /** 289 * Test for Bug 2 of HBASE-10466. 290 * "Bug 2: Conditions for the first flush of region close (so-called pre-flush) If memstoreSize 291 * is smaller than a certain value, or when region close starts a flush is ongoing, the first 292 * flush is skipped and only the second flush takes place. However, two flushes are required in 293 * case previous flush fails and leaves some data in snapshot. The bug could cause loss of data 294 * in current memstore. The fix is removing all conditions except abort check so we ensure 2 295 * flushes for region close." 296 * @throws IOException 297 */ 298 @Test 299 public void testCloseCarryingSnapshot() throws IOException { 300 HRegion region = initHRegion(tableName, method, CONF, COLUMN_FAMILY_BYTES); 301 HStore store = region.getStore(COLUMN_FAMILY_BYTES); 302 // Get some random bytes. 303 byte [] value = Bytes.toBytes(method); 304 // Make a random put against our cf. 305 Put put = new Put(value); 306 put.addColumn(COLUMN_FAMILY_BYTES, null, value); 307 // First put something in current memstore, which will be in snapshot after flusher.prepare() 308 region.put(put); 309 StoreFlushContext storeFlushCtx = store.createFlushContext(12345, FlushLifeCycleTracker.DUMMY); 310 storeFlushCtx.prepare(); 311 // Second put something in current memstore 312 put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("abc"), value); 313 region.put(put); 314 // Close with something in memstore and something in the snapshot. Make sure all is cleared. 315 region.close(); 316 assertEquals(0, region.getMemStoreDataSize()); 317 HBaseTestingUtility.closeRegionAndWAL(region); 318 } 319 320 /* 321 * This test is for verifying memstore snapshot size is correctly updated in case of rollback 322 * See HBASE-10845 323 */ 324 @Test 325 public void testMemstoreSnapshotSize() throws IOException { 326 class MyFaultyFSLog extends FaultyFSLog { 327 StoreFlushContext storeFlushCtx; 328 public MyFaultyFSLog(FileSystem fs, Path rootDir, String logName, Configuration conf) 329 throws IOException { 330 super(fs, rootDir, logName, conf); 331 } 332 333 void setStoreFlushCtx(StoreFlushContext storeFlushCtx) { 334 this.storeFlushCtx = storeFlushCtx; 335 } 336 337 @Override 338 public void sync(long txid) throws IOException { 339 storeFlushCtx.prepare(); 340 super.sync(txid); 341 } 342 } 343 344 FileSystem fs = FileSystem.get(CONF); 345 Path rootDir = new Path(dir + "testMemstoreSnapshotSize"); 346 MyFaultyFSLog faultyLog = new MyFaultyFSLog(fs, rootDir, "testMemstoreSnapshotSize", CONF); 347 HRegion region = initHRegion(tableName, null, null, false, Durability.SYNC_WAL, faultyLog, 348 COLUMN_FAMILY_BYTES); 349 350 HStore store = region.getStore(COLUMN_FAMILY_BYTES); 351 // Get some random bytes. 352 byte [] value = Bytes.toBytes(method); 353 faultyLog.setStoreFlushCtx(store.createFlushContext(12345, FlushLifeCycleTracker.DUMMY)); 354 355 Put put = new Put(value); 356 put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("abc"), value); 357 faultyLog.setFailureType(FaultyFSLog.FailureType.SYNC); 358 359 boolean threwIOE = false; 360 try { 361 region.put(put); 362 } catch (IOException ioe) { 363 threwIOE = true; 364 } finally { 365 assertTrue("The regionserver should have thrown an exception", threwIOE); 366 } 367 MemStoreSize mss = store.getFlushableSize(); 368 assertTrue("flushable size should be zero, but it is " + mss, 369 mss.getDataSize() == 0); 370 HBaseTestingUtility.closeRegionAndWAL(region); 371 } 372 373 /** 374 * Create a WAL outside of the usual helper in 375 * {@link HBaseTestingUtility#createWal(Configuration, Path, RegionInfo)} because that method 376 * doesn't play nicely with FaultyFileSystem. Call this method before overriding 377 * {@code fs.file.impl}. 378 * @param callingMethod a unique component for the path, probably the name of the test method. 379 */ 380 private static WAL createWALCompatibleWithFaultyFileSystem(String callingMethod, 381 Configuration conf, TableName tableName) throws IOException { 382 final Path logDir = TEST_UTIL.getDataTestDirOnTestFS(callingMethod + ".log"); 383 final Configuration walConf = new Configuration(conf); 384 FSUtils.setRootDir(walConf, logDir); 385 return new WALFactory(walConf, callingMethod) 386 .getWAL(RegionInfoBuilder.newBuilder(tableName).build()); 387 } 388 389 @Test 390 public void testMemstoreSizeAccountingWithFailedPostBatchMutate() throws IOException { 391 String testName = "testMemstoreSizeAccountingWithFailedPostBatchMutate"; 392 FileSystem fs = FileSystem.get(CONF); 393 Path rootDir = new Path(dir + testName); 394 FSHLog hLog = new FSHLog(fs, rootDir, testName, CONF); 395 HRegion region = initHRegion(tableName, null, null, false, Durability.SYNC_WAL, hLog, 396 COLUMN_FAMILY_BYTES); 397 HStore store = region.getStore(COLUMN_FAMILY_BYTES); 398 assertEquals(0, region.getMemStoreDataSize()); 399 400 // Put one value 401 byte [] value = Bytes.toBytes(method); 402 Put put = new Put(value); 403 put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("abc"), value); 404 region.put(put); 405 long onePutSize = region.getMemStoreDataSize(); 406 assertTrue(onePutSize > 0); 407 408 RegionCoprocessorHost mockedCPHost = Mockito.mock(RegionCoprocessorHost.class); 409 doThrow(new IOException()) 410 .when(mockedCPHost).postBatchMutate(Mockito.<MiniBatchOperationInProgress<Mutation>>any()); 411 region.setCoprocessorHost(mockedCPHost); 412 413 put = new Put(value); 414 put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("dfg"), value); 415 try { 416 region.put(put); 417 fail("Should have failed with IOException"); 418 } catch (IOException expected) { 419 } 420 long expectedSize = onePutSize * 2; 421 assertEquals("memstoreSize should be incremented", 422 expectedSize, region.getMemStoreDataSize()); 423 assertEquals("flushable size should be incremented", 424 expectedSize, store.getFlushableSize().getDataSize()); 425 426 region.setCoprocessorHost(null); 427 HBaseTestingUtility.closeRegionAndWAL(region); 428 } 429 430 /** 431 * A test case of HBASE-21041 432 * @throws Exception Exception 433 */ 434 @Test 435 public void testFlushAndMemstoreSizeCounting() throws Exception { 436 byte[] family = Bytes.toBytes("family"); 437 this.region = initHRegion(tableName, method, CONF, family); 438 final WALFactory wals = new WALFactory(CONF, method); 439 try { 440 for (byte[] row : HBaseTestingUtility.ROWS) { 441 Put put = new Put(row); 442 put.addColumn(family, family, row); 443 region.put(put); 444 } 445 region.flush(true); 446 // After flush, data size should be zero 447 assertEquals(0, region.getMemStoreDataSize()); 448 // After flush, a new active mutable segment is created, so the heap size 449 // should equal to MutableSegment.DEEP_OVERHEAD 450 assertEquals(MutableSegment.DEEP_OVERHEAD, region.getMemStoreHeapSize()); 451 // After flush, offheap should be zero 452 assertEquals(0, region.getMemStoreOffHeapSize()); 453 } finally { 454 HBaseTestingUtility.closeRegionAndWAL(this.region); 455 this.region = null; 456 wals.close(); 457 } 458 } 459 460 /** 461 * Test we do not lose data if we fail a flush and then close. 462 * Part of HBase-10466. Tests the following from the issue description: 463 * "Bug 1: Wrong calculation of HRegion.memstoreSize: When a flush fails, data to be flushed is 464 * kept in each MemStore's snapshot and wait for next flush attempt to continue on it. But when 465 * the next flush succeeds, the counter of total memstore size in HRegion is always deduced by 466 * the sum of current memstore sizes instead of snapshots left from previous failed flush. This 467 * calculation is problematic that almost every time there is failed flush, HRegion.memstoreSize 468 * gets reduced by a wrong value. If region flush could not proceed for a couple cycles, the size 469 * in current memstore could be much larger than the snapshot. It's likely to drift memstoreSize 470 * much smaller than expected. In extreme case, if the error accumulates to even bigger than 471 * HRegion's memstore size limit, any further flush is skipped because flush does not do anything 472 * if memstoreSize is not larger than 0." 473 * @throws Exception 474 */ 475 @Test 476 public void testFlushSizeAccounting() throws Exception { 477 final Configuration conf = HBaseConfiguration.create(CONF); 478 final WAL wal = createWALCompatibleWithFaultyFileSystem(method, conf, tableName); 479 // Only retry once. 480 conf.setInt("hbase.hstore.flush.retries.number", 1); 481 final User user = 482 User.createUserForTesting(conf, method, new String[]{"foo"}); 483 // Inject our faulty LocalFileSystem 484 conf.setClass("fs.file.impl", FaultyFileSystem.class, FileSystem.class); 485 user.runAs(new PrivilegedExceptionAction<Object>() { 486 @Override 487 public Object run() throws Exception { 488 // Make sure it worked (above is sensitive to caching details in hadoop core) 489 FileSystem fs = FileSystem.get(conf); 490 Assert.assertEquals(FaultyFileSystem.class, fs.getClass()); 491 FaultyFileSystem ffs = (FaultyFileSystem)fs; 492 HRegion region = null; 493 try { 494 // Initialize region 495 region = initHRegion(tableName, null, null, false, Durability.SYNC_WAL, wal, 496 COLUMN_FAMILY_BYTES); 497 long size = region.getMemStoreDataSize(); 498 Assert.assertEquals(0, size); 499 // Put one item into memstore. Measure the size of one item in memstore. 500 Put p1 = new Put(row); 501 p1.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual1, 1, (byte[]) null)); 502 region.put(p1); 503 final long sizeOfOnePut = region.getMemStoreDataSize(); 504 // Fail a flush which means the current memstore will hang out as memstore 'snapshot'. 505 try { 506 LOG.info("Flushing"); 507 region.flush(true); 508 Assert.fail("Didn't bubble up IOE!"); 509 } catch (DroppedSnapshotException dse) { 510 // What we are expecting 511 region.closing.set(false); // this is needed for the rest of the test to work 512 } 513 // Make it so all writes succeed from here on out 514 ffs.fault.set(false); 515 // Check sizes. Should still be the one entry. 516 Assert.assertEquals(sizeOfOnePut, region.getMemStoreDataSize()); 517 // Now add two entries so that on this next flush that fails, we can see if we 518 // subtract the right amount, the snapshot size only. 519 Put p2 = new Put(row); 520 p2.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual2, 2, (byte[])null)); 521 p2.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual3, 3, (byte[])null)); 522 region.put(p2); 523 long expectedSize = sizeOfOnePut * 3; 524 Assert.assertEquals(expectedSize, region.getMemStoreDataSize()); 525 // Do a successful flush. It will clear the snapshot only. Thats how flushes work. 526 // If already a snapshot, we clear it else we move the memstore to be snapshot and flush 527 // it 528 region.flush(true); 529 // Make sure our memory accounting is right. 530 Assert.assertEquals(sizeOfOnePut * 2, region.getMemStoreDataSize()); 531 } finally { 532 HBaseTestingUtility.closeRegionAndWAL(region); 533 } 534 return null; 535 } 536 }); 537 FileSystem.closeAllForUGI(user.getUGI()); 538 } 539 540 @Test 541 public void testCloseWithFailingFlush() throws Exception { 542 final Configuration conf = HBaseConfiguration.create(CONF); 543 final WAL wal = createWALCompatibleWithFaultyFileSystem(method, conf, tableName); 544 // Only retry once. 545 conf.setInt("hbase.hstore.flush.retries.number", 1); 546 final User user = 547 User.createUserForTesting(conf, this.method, new String[]{"foo"}); 548 // Inject our faulty LocalFileSystem 549 conf.setClass("fs.file.impl", FaultyFileSystem.class, FileSystem.class); 550 user.runAs(new PrivilegedExceptionAction<Object>() { 551 @Override 552 public Object run() throws Exception { 553 // Make sure it worked (above is sensitive to caching details in hadoop core) 554 FileSystem fs = FileSystem.get(conf); 555 Assert.assertEquals(FaultyFileSystem.class, fs.getClass()); 556 FaultyFileSystem ffs = (FaultyFileSystem)fs; 557 HRegion region = null; 558 try { 559 // Initialize region 560 region = initHRegion(tableName, null, null, false, 561 Durability.SYNC_WAL, wal, COLUMN_FAMILY_BYTES); 562 long size = region.getMemStoreDataSize(); 563 Assert.assertEquals(0, size); 564 // Put one item into memstore. Measure the size of one item in memstore. 565 Put p1 = new Put(row); 566 p1.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual1, 1, (byte[])null)); 567 region.put(p1); 568 // Manufacture an outstanding snapshot -- fake a failed flush by doing prepare step only. 569 HStore store = region.getStore(COLUMN_FAMILY_BYTES); 570 StoreFlushContext storeFlushCtx = 571 store.createFlushContext(12345, FlushLifeCycleTracker.DUMMY); 572 storeFlushCtx.prepare(); 573 // Now add two entries to the foreground memstore. 574 Put p2 = new Put(row); 575 p2.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual2, 2, (byte[])null)); 576 p2.add(new KeyValue(row, COLUMN_FAMILY_BYTES, qual3, 3, (byte[])null)); 577 region.put(p2); 578 // Now try close on top of a failing flush. 579 region.close(); 580 fail(); 581 } catch (DroppedSnapshotException dse) { 582 // Expected 583 LOG.info("Expected DroppedSnapshotException"); 584 } finally { 585 // Make it so all writes succeed from here on out so can close clean 586 ffs.fault.set(false); 587 HBaseTestingUtility.closeRegionAndWAL(region); 588 } 589 return null; 590 } 591 }); 592 FileSystem.closeAllForUGI(user.getUGI()); 593 } 594 595 @Test 596 public void testCompactionAffectedByScanners() throws Exception { 597 byte[] family = Bytes.toBytes("family"); 598 this.region = initHRegion(tableName, method, CONF, family); 599 600 Put put = new Put(Bytes.toBytes("r1")); 601 put.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("v1")); 602 region.put(put); 603 region.flush(true); 604 605 Scan scan = new Scan(); 606 scan.setMaxVersions(3); 607 // open the first scanner 608 RegionScanner scanner1 = region.getScanner(scan); 609 610 Delete delete = new Delete(Bytes.toBytes("r1")); 611 region.delete(delete); 612 region.flush(true); 613 614 // open the second scanner 615 RegionScanner scanner2 = region.getScanner(scan); 616 617 List<Cell> results = new ArrayList<>(); 618 619 System.out.println("Smallest read point:" + region.getSmallestReadPoint()); 620 621 // make a major compaction 622 region.compact(true); 623 624 // open the third scanner 625 RegionScanner scanner3 = region.getScanner(scan); 626 627 // get data from scanner 1, 2, 3 after major compaction 628 scanner1.next(results); 629 System.out.println(results); 630 assertEquals(1, results.size()); 631 632 results.clear(); 633 scanner2.next(results); 634 System.out.println(results); 635 assertEquals(0, results.size()); 636 637 results.clear(); 638 scanner3.next(results); 639 System.out.println(results); 640 assertEquals(0, results.size()); 641 } 642 643 @Test 644 public void testToShowNPEOnRegionScannerReseek() throws Exception { 645 byte[] family = Bytes.toBytes("family"); 646 this.region = initHRegion(tableName, method, CONF, family); 647 648 Put put = new Put(Bytes.toBytes("r1")); 649 put.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("v1")); 650 region.put(put); 651 put = new Put(Bytes.toBytes("r2")); 652 put.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("v1")); 653 region.put(put); 654 region.flush(true); 655 656 Scan scan = new Scan(); 657 scan.setMaxVersions(3); 658 // open the first scanner 659 RegionScanner scanner1 = region.getScanner(scan); 660 661 System.out.println("Smallest read point:" + region.getSmallestReadPoint()); 662 663 region.compact(true); 664 665 scanner1.reseek(Bytes.toBytes("r2")); 666 List<Cell> results = new ArrayList<>(); 667 scanner1.next(results); 668 Cell keyValue = results.get(0); 669 Assert.assertTrue(Bytes.compareTo(CellUtil.cloneRow(keyValue), Bytes.toBytes("r2")) == 0); 670 scanner1.close(); 671 } 672 673 @Test 674 public void testSkipRecoveredEditsReplay() throws Exception { 675 byte[] family = Bytes.toBytes("family"); 676 this.region = initHRegion(tableName, method, CONF, family); 677 final WALFactory wals = new WALFactory(CONF, method); 678 try { 679 Path regiondir = region.getRegionFileSystem().getRegionDir(); 680 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 681 byte[] regionName = region.getRegionInfo().getEncodedNameAsBytes(); 682 683 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 684 685 long maxSeqId = 1050; 686 long minSeqId = 1000; 687 688 for (long i = minSeqId; i <= maxSeqId; i += 10) { 689 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", i)); 690 fs.create(recoveredEdits); 691 WALProvider.Writer writer = wals.createRecoveredEditsWriter(fs, recoveredEdits); 692 693 long time = System.nanoTime(); 694 WALEdit edit = new WALEdit(); 695 edit.add(new KeyValue(row, family, Bytes.toBytes(i), time, KeyValue.Type.Put, Bytes 696 .toBytes(i))); 697 writer.append(new WAL.Entry(new WALKeyImpl(regionName, tableName, i, time, 698 HConstants.DEFAULT_CLUSTER_ID), edit)); 699 700 writer.close(); 701 } 702 MonitoredTask status = TaskMonitor.get().createStatus(method); 703 Map<byte[], Long> maxSeqIdInStores = new TreeMap<>(Bytes.BYTES_COMPARATOR); 704 for (HStore store : region.getStores()) { 705 maxSeqIdInStores.put(Bytes.toBytes(store.getColumnFamilyName()), minSeqId - 1); 706 } 707 long seqId = region.replayRecoveredEditsIfAny(maxSeqIdInStores, null, status); 708 assertEquals(maxSeqId, seqId); 709 region.getMVCC().advanceTo(seqId); 710 Get get = new Get(row); 711 Result result = region.get(get); 712 for (long i = minSeqId; i <= maxSeqId; i += 10) { 713 List<Cell> kvs = result.getColumnCells(family, Bytes.toBytes(i)); 714 assertEquals(1, kvs.size()); 715 assertArrayEquals(Bytes.toBytes(i), CellUtil.cloneValue(kvs.get(0))); 716 } 717 } finally { 718 HBaseTestingUtility.closeRegionAndWAL(this.region); 719 this.region = null; 720 wals.close(); 721 } 722 } 723 724 @Test 725 public void testSkipRecoveredEditsReplaySomeIgnored() throws Exception { 726 byte[] family = Bytes.toBytes("family"); 727 this.region = initHRegion(tableName, method, CONF, family); 728 final WALFactory wals = new WALFactory(CONF, method); 729 try { 730 Path regiondir = region.getRegionFileSystem().getRegionDir(); 731 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 732 byte[] regionName = region.getRegionInfo().getEncodedNameAsBytes(); 733 734 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 735 736 long maxSeqId = 1050; 737 long minSeqId = 1000; 738 739 for (long i = minSeqId; i <= maxSeqId; i += 10) { 740 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", i)); 741 fs.create(recoveredEdits); 742 WALProvider.Writer writer = wals.createRecoveredEditsWriter(fs, recoveredEdits); 743 744 long time = System.nanoTime(); 745 WALEdit edit = new WALEdit(); 746 edit.add(new KeyValue(row, family, Bytes.toBytes(i), time, KeyValue.Type.Put, Bytes 747 .toBytes(i))); 748 writer.append(new WAL.Entry(new WALKeyImpl(regionName, tableName, i, time, 749 HConstants.DEFAULT_CLUSTER_ID), edit)); 750 751 writer.close(); 752 } 753 long recoverSeqId = 1030; 754 MonitoredTask status = TaskMonitor.get().createStatus(method); 755 Map<byte[], Long> maxSeqIdInStores = new TreeMap<>(Bytes.BYTES_COMPARATOR); 756 for (HStore store : region.getStores()) { 757 maxSeqIdInStores.put(Bytes.toBytes(store.getColumnFamilyName()), recoverSeqId - 1); 758 } 759 long seqId = region.replayRecoveredEditsIfAny(maxSeqIdInStores, null, status); 760 assertEquals(maxSeqId, seqId); 761 region.getMVCC().advanceTo(seqId); 762 Get get = new Get(row); 763 Result result = region.get(get); 764 for (long i = minSeqId; i <= maxSeqId; i += 10) { 765 List<Cell> kvs = result.getColumnCells(family, Bytes.toBytes(i)); 766 if (i < recoverSeqId) { 767 assertEquals(0, kvs.size()); 768 } else { 769 assertEquals(1, kvs.size()); 770 assertArrayEquals(Bytes.toBytes(i), CellUtil.cloneValue(kvs.get(0))); 771 } 772 } 773 } finally { 774 HBaseTestingUtility.closeRegionAndWAL(this.region); 775 this.region = null; 776 wals.close(); 777 } 778 } 779 780 @Test 781 public void testSkipRecoveredEditsReplayAllIgnored() throws Exception { 782 byte[] family = Bytes.toBytes("family"); 783 this.region = initHRegion(tableName, method, CONF, family); 784 try { 785 Path regiondir = region.getRegionFileSystem().getRegionDir(); 786 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 787 788 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 789 for (int i = 1000; i < 1050; i += 10) { 790 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", i)); 791 FSDataOutputStream dos = fs.create(recoveredEdits); 792 dos.writeInt(i); 793 dos.close(); 794 } 795 long minSeqId = 2000; 796 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", minSeqId - 1)); 797 FSDataOutputStream dos = fs.create(recoveredEdits); 798 dos.close(); 799 800 Map<byte[], Long> maxSeqIdInStores = new TreeMap<>(Bytes.BYTES_COMPARATOR); 801 for (HStore store : region.getStores()) { 802 maxSeqIdInStores.put(Bytes.toBytes(store.getColumnFamilyName()), minSeqId); 803 } 804 long seqId = region.replayRecoveredEditsIfAny(maxSeqIdInStores, null, null); 805 assertEquals(minSeqId, seqId); 806 } finally { 807 HBaseTestingUtility.closeRegionAndWAL(this.region); 808 this.region = null; 809 } 810 } 811 812 @Test 813 public void testSkipRecoveredEditsReplayTheLastFileIgnored() throws Exception { 814 byte[] family = Bytes.toBytes("family"); 815 this.region = initHRegion(tableName, method, CONF, family); 816 final WALFactory wals = new WALFactory(CONF, method); 817 try { 818 Path regiondir = region.getRegionFileSystem().getRegionDir(); 819 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 820 byte[] regionName = region.getRegionInfo().getEncodedNameAsBytes(); 821 byte[][] columns = region.getTableDescriptor().getColumnFamilyNames().toArray(new byte[0][]); 822 823 assertEquals(0, region.getStoreFileList(columns).size()); 824 825 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 826 827 long maxSeqId = 1050; 828 long minSeqId = 1000; 829 830 for (long i = minSeqId; i <= maxSeqId; i += 10) { 831 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", i)); 832 fs.create(recoveredEdits); 833 WALProvider.Writer writer = wals.createRecoveredEditsWriter(fs, recoveredEdits); 834 835 long time = System.nanoTime(); 836 WALEdit edit = null; 837 if (i == maxSeqId) { 838 edit = WALEdit.createCompaction(region.getRegionInfo(), 839 CompactionDescriptor.newBuilder() 840 .setTableName(ByteString.copyFrom(tableName.getName())) 841 .setFamilyName(ByteString.copyFrom(regionName)) 842 .setEncodedRegionName(ByteString.copyFrom(regionName)) 843 .setStoreHomeDirBytes(ByteString.copyFrom(Bytes.toBytes(regiondir.toString()))) 844 .setRegionName(ByteString.copyFrom(region.getRegionInfo().getRegionName())) 845 .build()); 846 } else { 847 edit = new WALEdit(); 848 edit.add(new KeyValue(row, family, Bytes.toBytes(i), time, KeyValue.Type.Put, Bytes 849 .toBytes(i))); 850 } 851 writer.append(new WAL.Entry(new WALKeyImpl(regionName, tableName, i, time, 852 HConstants.DEFAULT_CLUSTER_ID), edit)); 853 writer.close(); 854 } 855 856 long recoverSeqId = 1030; 857 Map<byte[], Long> maxSeqIdInStores = new TreeMap<>(Bytes.BYTES_COMPARATOR); 858 MonitoredTask status = TaskMonitor.get().createStatus(method); 859 for (HStore store : region.getStores()) { 860 maxSeqIdInStores.put(Bytes.toBytes(store.getColumnFamilyName()), recoverSeqId - 1); 861 } 862 long seqId = region.replayRecoveredEditsIfAny(maxSeqIdInStores, null, status); 863 assertEquals(maxSeqId, seqId); 864 865 // assert that the files are flushed 866 assertEquals(1, region.getStoreFileList(columns).size()); 867 868 } finally { 869 HBaseTestingUtility.closeRegionAndWAL(this.region); 870 this.region = null; 871 wals.close(); 872 } 873 } 874 875 @Test 876 public void testRecoveredEditsReplayCompaction() throws Exception { 877 testRecoveredEditsReplayCompaction(false); 878 testRecoveredEditsReplayCompaction(true); 879 } 880 881 public void testRecoveredEditsReplayCompaction(boolean mismatchedRegionName) throws Exception { 882 CONF.setClass(HConstants.REGION_IMPL, HRegionForTesting.class, Region.class); 883 byte[] family = Bytes.toBytes("family"); 884 this.region = initHRegion(tableName, method, CONF, family); 885 final WALFactory wals = new WALFactory(CONF, method); 886 try { 887 Path regiondir = region.getRegionFileSystem().getRegionDir(); 888 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 889 byte[] regionName = region.getRegionInfo().getEncodedNameAsBytes(); 890 891 long maxSeqId = 3; 892 long minSeqId = 0; 893 894 for (long i = minSeqId; i < maxSeqId; i++) { 895 Put put = new Put(Bytes.toBytes(i)); 896 put.addColumn(family, Bytes.toBytes(i), Bytes.toBytes(i)); 897 region.put(put); 898 region.flush(true); 899 } 900 901 // this will create a region with 3 files 902 assertEquals(3, region.getStore(family).getStorefilesCount()); 903 List<Path> storeFiles = new ArrayList<>(3); 904 for (HStoreFile sf : region.getStore(family).getStorefiles()) { 905 storeFiles.add(sf.getPath()); 906 } 907 908 // disable compaction completion 909 CONF.setBoolean("hbase.hstore.compaction.complete", false); 910 region.compactStores(); 911 912 // ensure that nothing changed 913 assertEquals(3, region.getStore(family).getStorefilesCount()); 914 915 // now find the compacted file, and manually add it to the recovered edits 916 Path tmpDir = new Path(region.getRegionFileSystem().getTempDir(), Bytes.toString(family)); 917 FileStatus[] files = FSUtils.listStatus(fs, tmpDir); 918 String errorMsg = "Expected to find 1 file in the region temp directory " 919 + "from the compaction, could not find any"; 920 assertNotNull(errorMsg, files); 921 assertEquals(errorMsg, 1, files.length); 922 // move the file inside region dir 923 Path newFile = region.getRegionFileSystem().commitStoreFile(Bytes.toString(family), 924 files[0].getPath()); 925 926 byte[] encodedNameAsBytes = this.region.getRegionInfo().getEncodedNameAsBytes(); 927 byte[] fakeEncodedNameAsBytes = new byte [encodedNameAsBytes.length]; 928 for (int i=0; i < encodedNameAsBytes.length; i++) { 929 // Mix the byte array to have a new encodedName 930 fakeEncodedNameAsBytes[i] = (byte) (encodedNameAsBytes[i] + 1); 931 } 932 933 CompactionDescriptor compactionDescriptor = ProtobufUtil.toCompactionDescriptor(this.region 934 .getRegionInfo(), mismatchedRegionName ? fakeEncodedNameAsBytes : null, family, 935 storeFiles, Lists.newArrayList(newFile), 936 region.getRegionFileSystem().getStoreDir(Bytes.toString(family))); 937 938 WALUtil.writeCompactionMarker(region.getWAL(), this.region.getReplicationScope(), 939 this.region.getRegionInfo(), compactionDescriptor, region.getMVCC()); 940 941 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 942 943 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", 1000)); 944 fs.create(recoveredEdits); 945 WALProvider.Writer writer = wals.createRecoveredEditsWriter(fs, recoveredEdits); 946 947 long time = System.nanoTime(); 948 949 writer.append(new WAL.Entry(new WALKeyImpl(regionName, tableName, 10, time, 950 HConstants.DEFAULT_CLUSTER_ID), WALEdit.createCompaction(region.getRegionInfo(), 951 compactionDescriptor))); 952 writer.close(); 953 954 // close the region now, and reopen again 955 region.getTableDescriptor(); 956 region.getRegionInfo(); 957 region.close(); 958 try { 959 region = HRegion.openHRegion(region, null); 960 } catch (WrongRegionException wre) { 961 fail("Matching encoded region name should not have produced WrongRegionException"); 962 } 963 964 // now check whether we have only one store file, the compacted one 965 Collection<HStoreFile> sfs = region.getStore(family).getStorefiles(); 966 for (HStoreFile sf : sfs) { 967 LOG.info(Objects.toString(sf.getPath())); 968 } 969 if (!mismatchedRegionName) { 970 assertEquals(1, region.getStore(family).getStorefilesCount()); 971 } 972 files = FSUtils.listStatus(fs, tmpDir); 973 assertTrue("Expected to find 0 files inside " + tmpDir, files == null || files.length == 0); 974 975 for (long i = minSeqId; i < maxSeqId; i++) { 976 Get get = new Get(Bytes.toBytes(i)); 977 Result result = region.get(get); 978 byte[] value = result.getValue(family, Bytes.toBytes(i)); 979 assertArrayEquals(Bytes.toBytes(i), value); 980 } 981 } finally { 982 HBaseTestingUtility.closeRegionAndWAL(this.region); 983 this.region = null; 984 wals.close(); 985 CONF.setClass(HConstants.REGION_IMPL, HRegion.class, Region.class); 986 } 987 } 988 989 @Test 990 public void testFlushMarkers() throws Exception { 991 // tests that flush markers are written to WAL and handled at recovered edits 992 byte[] family = Bytes.toBytes("family"); 993 Path logDir = TEST_UTIL.getDataTestDirOnTestFS(method + ".log"); 994 final Configuration walConf = new Configuration(TEST_UTIL.getConfiguration()); 995 FSUtils.setRootDir(walConf, logDir); 996 final WALFactory wals = new WALFactory(walConf, method); 997 final WAL wal = wals.getWAL(RegionInfoBuilder.newBuilder(tableName).build()); 998 999 this.region = initHRegion(tableName, HConstants.EMPTY_START_ROW, 1000 HConstants.EMPTY_END_ROW, false, Durability.USE_DEFAULT, wal, family); 1001 try { 1002 Path regiondir = region.getRegionFileSystem().getRegionDir(); 1003 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 1004 byte[] regionName = region.getRegionInfo().getEncodedNameAsBytes(); 1005 1006 long maxSeqId = 3; 1007 long minSeqId = 0; 1008 1009 for (long i = minSeqId; i < maxSeqId; i++) { 1010 Put put = new Put(Bytes.toBytes(i)); 1011 put.addColumn(family, Bytes.toBytes(i), Bytes.toBytes(i)); 1012 region.put(put); 1013 region.flush(true); 1014 } 1015 1016 // this will create a region with 3 files from flush 1017 assertEquals(3, region.getStore(family).getStorefilesCount()); 1018 List<String> storeFiles = new ArrayList<>(3); 1019 for (HStoreFile sf : region.getStore(family).getStorefiles()) { 1020 storeFiles.add(sf.getPath().getName()); 1021 } 1022 1023 // now verify that the flush markers are written 1024 wal.shutdown(); 1025 WAL.Reader reader = WALFactory.createReader(fs, AbstractFSWALProvider.getCurrentFileName(wal), 1026 TEST_UTIL.getConfiguration()); 1027 try { 1028 List<WAL.Entry> flushDescriptors = new ArrayList<>(); 1029 long lastFlushSeqId = -1; 1030 while (true) { 1031 WAL.Entry entry = reader.next(); 1032 if (entry == null) { 1033 break; 1034 } 1035 Cell cell = entry.getEdit().getCells().get(0); 1036 if (WALEdit.isMetaEditFamily(cell)) { 1037 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(cell); 1038 assertNotNull(flushDesc); 1039 assertArrayEquals(tableName.getName(), flushDesc.getTableName().toByteArray()); 1040 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 1041 assertTrue(flushDesc.getFlushSequenceNumber() > lastFlushSeqId); 1042 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 1043 assertTrue(flushDesc.getFlushSequenceNumber() == lastFlushSeqId); 1044 } 1045 lastFlushSeqId = flushDesc.getFlushSequenceNumber(); 1046 assertArrayEquals(regionName, flushDesc.getEncodedRegionName().toByteArray()); 1047 assertEquals(1, flushDesc.getStoreFlushesCount()); //only one store 1048 StoreFlushDescriptor storeFlushDesc = flushDesc.getStoreFlushes(0); 1049 assertArrayEquals(family, storeFlushDesc.getFamilyName().toByteArray()); 1050 assertEquals("family", storeFlushDesc.getStoreHomeDir()); 1051 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 1052 assertEquals(0, storeFlushDesc.getFlushOutputCount()); 1053 } else { 1054 assertEquals(1, storeFlushDesc.getFlushOutputCount()); //only one file from flush 1055 assertTrue(storeFiles.contains(storeFlushDesc.getFlushOutput(0))); 1056 } 1057 1058 flushDescriptors.add(entry); 1059 } 1060 } 1061 1062 assertEquals(3 * 2, flushDescriptors.size()); // START_FLUSH and COMMIT_FLUSH per flush 1063 1064 // now write those markers to the recovered edits again. 1065 1066 Path recoveredEditsDir = WALSplitter.getRegionDirRecoveredEditsDir(regiondir); 1067 1068 Path recoveredEdits = new Path(recoveredEditsDir, String.format("%019d", 1000)); 1069 fs.create(recoveredEdits); 1070 WALProvider.Writer writer = wals.createRecoveredEditsWriter(fs, recoveredEdits); 1071 1072 for (WAL.Entry entry : flushDescriptors) { 1073 writer.append(entry); 1074 } 1075 writer.close(); 1076 } finally { 1077 if (null != reader) { 1078 try { 1079 reader.close(); 1080 } catch (IOException exception) { 1081 LOG.warn("Problem closing wal: " + exception.getMessage()); 1082 LOG.debug("exception details", exception); 1083 } 1084 } 1085 } 1086 1087 1088 // close the region now, and reopen again 1089 region.close(); 1090 region = HRegion.openHRegion(region, null); 1091 1092 // now check whether we have can read back the data from region 1093 for (long i = minSeqId; i < maxSeqId; i++) { 1094 Get get = new Get(Bytes.toBytes(i)); 1095 Result result = region.get(get); 1096 byte[] value = result.getValue(family, Bytes.toBytes(i)); 1097 assertArrayEquals(Bytes.toBytes(i), value); 1098 } 1099 } finally { 1100 HBaseTestingUtility.closeRegionAndWAL(this.region); 1101 this.region = null; 1102 wals.close(); 1103 } 1104 } 1105 1106 static class IsFlushWALMarker implements ArgumentMatcher<WALEdit> { 1107 volatile FlushAction[] actions; 1108 public IsFlushWALMarker(FlushAction... actions) { 1109 this.actions = actions; 1110 } 1111 @Override 1112 public boolean matches(WALEdit edit) { 1113 List<Cell> cells = edit.getCells(); 1114 if (cells.isEmpty()) { 1115 return false; 1116 } 1117 if (WALEdit.isMetaEditFamily(cells.get(0))) { 1118 FlushDescriptor desc; 1119 try { 1120 desc = WALEdit.getFlushDescriptor(cells.get(0)); 1121 } catch (IOException e) { 1122 LOG.warn(e.toString(), e); 1123 return false; 1124 } 1125 if (desc != null) { 1126 for (FlushAction action : actions) { 1127 if (desc.getAction() == action) { 1128 return true; 1129 } 1130 } 1131 } 1132 } 1133 return false; 1134 } 1135 public IsFlushWALMarker set(FlushAction... actions) { 1136 this.actions = actions; 1137 return this; 1138 } 1139 } 1140 1141 @Test 1142 public void testFlushMarkersWALFail() throws Exception { 1143 // test the cases where the WAL append for flush markers fail. 1144 byte[] family = Bytes.toBytes("family"); 1145 1146 // spy an actual WAL implementation to throw exception (was not able to mock) 1147 Path logDir = TEST_UTIL.getDataTestDirOnTestFS(method + "log"); 1148 1149 final Configuration walConf = new Configuration(TEST_UTIL.getConfiguration()); 1150 FSUtils.setRootDir(walConf, logDir); 1151 // Make up a WAL that we can manipulate at append time. 1152 class FailAppendFlushMarkerWAL extends FSHLog { 1153 volatile FlushAction [] flushActions = null; 1154 1155 public FailAppendFlushMarkerWAL(FileSystem fs, Path root, String logDir, Configuration conf) 1156 throws IOException { 1157 super(fs, root, logDir, conf); 1158 } 1159 1160 @Override 1161 protected Writer createWriterInstance(Path path) throws IOException { 1162 final Writer w = super.createWriterInstance(path); 1163 return new Writer() { 1164 @Override 1165 public void close() throws IOException { 1166 w.close(); 1167 } 1168 1169 @Override 1170 public void sync() throws IOException { 1171 w.sync(); 1172 } 1173 1174 @Override 1175 public void append(Entry entry) throws IOException { 1176 List<Cell> cells = entry.getEdit().getCells(); 1177 if (WALEdit.isMetaEditFamily(cells.get(0))) { 1178 FlushDescriptor desc = WALEdit.getFlushDescriptor(cells.get(0)); 1179 if (desc != null) { 1180 for (FlushAction flushAction: flushActions) { 1181 if (desc.getAction().equals(flushAction)) { 1182 throw new IOException("Failed to append flush marker! " + flushAction); 1183 } 1184 } 1185 } 1186 } 1187 w.append(entry); 1188 } 1189 1190 @Override 1191 public long getLength() { 1192 return w.getLength(); 1193 } 1194 }; 1195 } 1196 } 1197 FailAppendFlushMarkerWAL wal = 1198 new FailAppendFlushMarkerWAL(FileSystem.get(walConf), FSUtils.getRootDir(walConf), 1199 method, walConf); 1200 this.region = initHRegion(tableName, HConstants.EMPTY_START_ROW, 1201 HConstants.EMPTY_END_ROW, false, Durability.USE_DEFAULT, wal, family); 1202 try { 1203 int i = 0; 1204 Put put = new Put(Bytes.toBytes(i)); 1205 put.setDurability(Durability.SKIP_WAL); // have to skip mocked wal 1206 put.addColumn(family, Bytes.toBytes(i), Bytes.toBytes(i)); 1207 region.put(put); 1208 1209 // 1. Test case where START_FLUSH throws exception 1210 wal.flushActions = new FlushAction [] {FlushAction.START_FLUSH}; 1211 1212 // start cache flush will throw exception 1213 try { 1214 region.flush(true); 1215 fail("This should have thrown exception"); 1216 } catch (DroppedSnapshotException unexpected) { 1217 // this should not be a dropped snapshot exception. Meaning that RS will not abort 1218 throw unexpected; 1219 } catch (IOException expected) { 1220 // expected 1221 } 1222 // The WAL is hosed now. It has two edits appended. We cannot roll the log without it 1223 // throwing a DroppedSnapshotException to force an abort. Just clean up the mess. 1224 region.close(true); 1225 wal.close(); 1226 1227 // 2. Test case where START_FLUSH succeeds but COMMIT_FLUSH will throw exception 1228 wal.flushActions = new FlushAction [] {FlushAction.COMMIT_FLUSH}; 1229 wal = new FailAppendFlushMarkerWAL(FileSystem.get(walConf), FSUtils.getRootDir(walConf), 1230 method, walConf); 1231 1232 this.region = initHRegion(tableName, HConstants.EMPTY_START_ROW, 1233 HConstants.EMPTY_END_ROW, false, Durability.USE_DEFAULT, wal, family); 1234 region.put(put); 1235 1236 // 3. Test case where ABORT_FLUSH will throw exception. 1237 // Even if ABORT_FLUSH throws exception, we should not fail with IOE, but continue with 1238 // DroppedSnapshotException. Below COMMMIT_FLUSH will cause flush to abort 1239 wal.flushActions = new FlushAction [] {FlushAction.COMMIT_FLUSH, FlushAction.ABORT_FLUSH}; 1240 1241 try { 1242 region.flush(true); 1243 fail("This should have thrown exception"); 1244 } catch (DroppedSnapshotException expected) { 1245 // we expect this exception, since we were able to write the snapshot, but failed to 1246 // write the flush marker to WAL 1247 } catch (IOException unexpected) { 1248 throw unexpected; 1249 } 1250 1251 } finally { 1252 HBaseTestingUtility.closeRegionAndWAL(this.region); 1253 this.region = null; 1254 } 1255 } 1256 1257 @Test 1258 public void testGetWhileRegionClose() throws IOException { 1259 Configuration hc = initSplit(); 1260 int numRows = 100; 1261 byte[][] families = { fam1, fam2, fam3 }; 1262 1263 // Setting up region 1264 this.region = initHRegion(tableName, method, hc, families); 1265 try { 1266 // Put data in region 1267 final int startRow = 100; 1268 putData(startRow, numRows, qual1, families); 1269 putData(startRow, numRows, qual2, families); 1270 putData(startRow, numRows, qual3, families); 1271 final AtomicBoolean done = new AtomicBoolean(false); 1272 final AtomicInteger gets = new AtomicInteger(0); 1273 GetTillDoneOrException[] threads = new GetTillDoneOrException[10]; 1274 try { 1275 // Set ten threads running concurrently getting from the region. 1276 for (int i = 0; i < threads.length / 2; i++) { 1277 threads[i] = new GetTillDoneOrException(i, Bytes.toBytes("" + startRow), done, gets); 1278 threads[i].setDaemon(true); 1279 threads[i].start(); 1280 } 1281 // Artificially make the condition by setting closing flag explicitly. 1282 // I can't make the issue happen with a call to region.close(). 1283 this.region.closing.set(true); 1284 for (int i = threads.length / 2; i < threads.length; i++) { 1285 threads[i] = new GetTillDoneOrException(i, Bytes.toBytes("" + startRow), done, gets); 1286 threads[i].setDaemon(true); 1287 threads[i].start(); 1288 } 1289 } finally { 1290 if (this.region != null) { 1291 HBaseTestingUtility.closeRegionAndWAL(this.region); 1292 } 1293 } 1294 done.set(true); 1295 for (GetTillDoneOrException t : threads) { 1296 try { 1297 t.join(); 1298 } catch (InterruptedException e) { 1299 e.printStackTrace(); 1300 } 1301 if (t.e != null) { 1302 LOG.info("Exception=" + t.e); 1303 assertFalse("Found a NPE in " + t.getName(), t.e instanceof NullPointerException); 1304 } 1305 } 1306 } finally { 1307 HBaseTestingUtility.closeRegionAndWAL(this.region); 1308 this.region = null; 1309 } 1310 } 1311 1312 /* 1313 * Thread that does get on single row until 'done' flag is flipped. If an 1314 * exception causes us to fail, it records it. 1315 */ 1316 class GetTillDoneOrException extends Thread { 1317 private final Get g; 1318 private final AtomicBoolean done; 1319 private final AtomicInteger count; 1320 private Exception e; 1321 1322 GetTillDoneOrException(final int i, final byte[] r, final AtomicBoolean d, 1323 final AtomicInteger c) { 1324 super("getter." + i); 1325 this.g = new Get(r); 1326 this.done = d; 1327 this.count = c; 1328 } 1329 1330 @Override 1331 public void run() { 1332 while (!this.done.get()) { 1333 try { 1334 assertTrue(region.get(g).size() > 0); 1335 this.count.incrementAndGet(); 1336 } catch (Exception e) { 1337 this.e = e; 1338 break; 1339 } 1340 } 1341 } 1342 } 1343 1344 /* 1345 * An involved filter test. Has multiple column families and deletes in mix. 1346 */ 1347 @Test 1348 public void testWeirdCacheBehaviour() throws Exception { 1349 final TableName tableName = TableName.valueOf(name.getMethodName()); 1350 byte[][] FAMILIES = new byte[][] { Bytes.toBytes("trans-blob"), Bytes.toBytes("trans-type"), 1351 Bytes.toBytes("trans-date"), Bytes.toBytes("trans-tags"), Bytes.toBytes("trans-group") }; 1352 this.region = initHRegion(tableName, method, CONF, FAMILIES); 1353 try { 1354 String value = "this is the value"; 1355 String value2 = "this is some other value"; 1356 String keyPrefix1 = "prefix1"; 1357 String keyPrefix2 = "prefix2"; 1358 String keyPrefix3 = "prefix3"; 1359 putRows(this.region, 3, value, keyPrefix1); 1360 putRows(this.region, 3, value, keyPrefix2); 1361 putRows(this.region, 3, value, keyPrefix3); 1362 putRows(this.region, 3, value2, keyPrefix1); 1363 putRows(this.region, 3, value2, keyPrefix2); 1364 putRows(this.region, 3, value2, keyPrefix3); 1365 System.out.println("Checking values for key: " + keyPrefix1); 1366 assertEquals("Got back incorrect number of rows from scan", 3, 1367 getNumberOfRows(keyPrefix1, value2, this.region)); 1368 System.out.println("Checking values for key: " + keyPrefix2); 1369 assertEquals("Got back incorrect number of rows from scan", 3, 1370 getNumberOfRows(keyPrefix2, value2, this.region)); 1371 System.out.println("Checking values for key: " + keyPrefix3); 1372 assertEquals("Got back incorrect number of rows from scan", 3, 1373 getNumberOfRows(keyPrefix3, value2, this.region)); 1374 deleteColumns(this.region, value2, keyPrefix1); 1375 deleteColumns(this.region, value2, keyPrefix2); 1376 deleteColumns(this.region, value2, keyPrefix3); 1377 System.out.println("Starting important checks....."); 1378 assertEquals("Got back incorrect number of rows from scan: " + keyPrefix1, 0, 1379 getNumberOfRows(keyPrefix1, value2, this.region)); 1380 assertEquals("Got back incorrect number of rows from scan: " + keyPrefix2, 0, 1381 getNumberOfRows(keyPrefix2, value2, this.region)); 1382 assertEquals("Got back incorrect number of rows from scan: " + keyPrefix3, 0, 1383 getNumberOfRows(keyPrefix3, value2, this.region)); 1384 } finally { 1385 HBaseTestingUtility.closeRegionAndWAL(this.region); 1386 this.region = null; 1387 } 1388 } 1389 1390 @Test 1391 public void testAppendWithReadOnlyTable() throws Exception { 1392 final TableName tableName = TableName.valueOf(name.getMethodName()); 1393 this.region = initHRegion(tableName, method, CONF, true, Bytes.toBytes("somefamily")); 1394 boolean exceptionCaught = false; 1395 Append append = new Append(Bytes.toBytes("somerow")); 1396 append.setDurability(Durability.SKIP_WAL); 1397 append.addColumn(Bytes.toBytes("somefamily"), Bytes.toBytes("somequalifier"), 1398 Bytes.toBytes("somevalue")); 1399 try { 1400 region.append(append); 1401 } catch (IOException e) { 1402 exceptionCaught = true; 1403 } finally { 1404 HBaseTestingUtility.closeRegionAndWAL(this.region); 1405 this.region = null; 1406 } 1407 assertTrue(exceptionCaught == true); 1408 } 1409 1410 @Test 1411 public void testIncrWithReadOnlyTable() throws Exception { 1412 final TableName tableName = TableName.valueOf(name.getMethodName()); 1413 this.region = initHRegion(tableName, method, CONF, true, Bytes.toBytes("somefamily")); 1414 boolean exceptionCaught = false; 1415 Increment inc = new Increment(Bytes.toBytes("somerow")); 1416 inc.setDurability(Durability.SKIP_WAL); 1417 inc.addColumn(Bytes.toBytes("somefamily"), Bytes.toBytes("somequalifier"), 1L); 1418 try { 1419 region.increment(inc); 1420 } catch (IOException e) { 1421 exceptionCaught = true; 1422 } finally { 1423 HBaseTestingUtility.closeRegionAndWAL(this.region); 1424 this.region = null; 1425 } 1426 assertTrue(exceptionCaught == true); 1427 } 1428 1429 private void deleteColumns(HRegion r, String value, String keyPrefix) throws IOException { 1430 InternalScanner scanner = buildScanner(keyPrefix, value, r); 1431 int count = 0; 1432 boolean more = false; 1433 List<Cell> results = new ArrayList<>(); 1434 do { 1435 more = scanner.next(results); 1436 if (results != null && !results.isEmpty()) 1437 count++; 1438 else 1439 break; 1440 Delete delete = new Delete(CellUtil.cloneRow(results.get(0))); 1441 delete.addColumn(Bytes.toBytes("trans-tags"), Bytes.toBytes("qual2")); 1442 r.delete(delete); 1443 results.clear(); 1444 } while (more); 1445 assertEquals("Did not perform correct number of deletes", 3, count); 1446 } 1447 1448 private int getNumberOfRows(String keyPrefix, String value, HRegion r) throws Exception { 1449 InternalScanner resultScanner = buildScanner(keyPrefix, value, r); 1450 int numberOfResults = 0; 1451 List<Cell> results = new ArrayList<>(); 1452 boolean more = false; 1453 do { 1454 more = resultScanner.next(results); 1455 if (results != null && !results.isEmpty()) 1456 numberOfResults++; 1457 else 1458 break; 1459 for (Cell kv : results) { 1460 System.out.println("kv=" + kv.toString() + ", " + Bytes.toString(CellUtil.cloneValue(kv))); 1461 } 1462 results.clear(); 1463 } while (more); 1464 return numberOfResults; 1465 } 1466 1467 private InternalScanner buildScanner(String keyPrefix, String value, HRegion r) 1468 throws IOException { 1469 // Defaults FilterList.Operator.MUST_PASS_ALL. 1470 FilterList allFilters = new FilterList(); 1471 allFilters.addFilter(new PrefixFilter(Bytes.toBytes(keyPrefix))); 1472 // Only return rows where this column value exists in the row. 1473 SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("trans-tags"), 1474 Bytes.toBytes("qual2"), CompareOp.EQUAL, Bytes.toBytes(value)); 1475 filter.setFilterIfMissing(true); 1476 allFilters.addFilter(filter); 1477 Scan scan = new Scan(); 1478 scan.addFamily(Bytes.toBytes("trans-blob")); 1479 scan.addFamily(Bytes.toBytes("trans-type")); 1480 scan.addFamily(Bytes.toBytes("trans-date")); 1481 scan.addFamily(Bytes.toBytes("trans-tags")); 1482 scan.addFamily(Bytes.toBytes("trans-group")); 1483 scan.setFilter(allFilters); 1484 return r.getScanner(scan); 1485 } 1486 1487 private void putRows(HRegion r, int numRows, String value, String key) throws IOException { 1488 for (int i = 0; i < numRows; i++) { 1489 String row = key + "_" + i/* UUID.randomUUID().toString() */; 1490 System.out.println(String.format("Saving row: %s, with value %s", row, value)); 1491 Put put = new Put(Bytes.toBytes(row)); 1492 put.setDurability(Durability.SKIP_WAL); 1493 put.addColumn(Bytes.toBytes("trans-blob"), null, Bytes.toBytes("value for blob")); 1494 put.addColumn(Bytes.toBytes("trans-type"), null, Bytes.toBytes("statement")); 1495 put.addColumn(Bytes.toBytes("trans-date"), null, Bytes.toBytes("20090921010101999")); 1496 put.addColumn(Bytes.toBytes("trans-tags"), Bytes.toBytes("qual2"), Bytes.toBytes(value)); 1497 put.addColumn(Bytes.toBytes("trans-group"), null, Bytes.toBytes("adhocTransactionGroupId")); 1498 r.put(put); 1499 } 1500 } 1501 1502 @Test 1503 public void testFamilyWithAndWithoutColon() throws Exception { 1504 byte[] cf = Bytes.toBytes(COLUMN_FAMILY); 1505 this.region = initHRegion(tableName, method, CONF, cf); 1506 try { 1507 Put p = new Put(tableName.toBytes()); 1508 byte[] cfwithcolon = Bytes.toBytes(COLUMN_FAMILY + ":"); 1509 p.addColumn(cfwithcolon, cfwithcolon, cfwithcolon); 1510 boolean exception = false; 1511 try { 1512 this.region.put(p); 1513 } catch (NoSuchColumnFamilyException e) { 1514 exception = true; 1515 } 1516 assertTrue(exception); 1517 } finally { 1518 HBaseTestingUtility.closeRegionAndWAL(this.region); 1519 this.region = null; 1520 } 1521 } 1522 1523 @Test 1524 public void testBatchPut_whileNoRowLocksHeld() throws IOException { 1525 final Put[] puts = new Put[10]; 1526 MetricsWALSource source = CompatibilitySingletonFactory.getInstance(MetricsWALSource.class); 1527 try { 1528 long syncs = prepareRegionForBachPut(puts, source, false); 1529 1530 OperationStatus[] codes = this.region.batchMutate(puts); 1531 assertEquals(10, codes.length); 1532 for (int i = 0; i < 10; i++) { 1533 assertEquals(OperationStatusCode.SUCCESS, codes[i].getOperationStatusCode()); 1534 } 1535 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs + 1, source); 1536 1537 LOG.info("Next a batch put with one invalid family"); 1538 puts[5].addColumn(Bytes.toBytes("BAD_CF"), qual, value); 1539 codes = this.region.batchMutate(puts); 1540 assertEquals(10, codes.length); 1541 for (int i = 0; i < 10; i++) { 1542 assertEquals((i == 5) ? OperationStatusCode.BAD_FAMILY : OperationStatusCode.SUCCESS, 1543 codes[i].getOperationStatusCode()); 1544 } 1545 1546 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs + 2, source); 1547 } finally { 1548 HBaseTestingUtility.closeRegionAndWAL(this.region); 1549 this.region = null; 1550 } 1551 } 1552 1553 @Test 1554 public void testBatchPut_whileMultipleRowLocksHeld() throws Exception { 1555 final Put[] puts = new Put[10]; 1556 MetricsWALSource source = CompatibilitySingletonFactory.getInstance(MetricsWALSource.class); 1557 try { 1558 long syncs = prepareRegionForBachPut(puts, source, false); 1559 1560 puts[5].addColumn(Bytes.toBytes("BAD_CF"), qual, value); 1561 1562 LOG.info("batchPut will have to break into four batches to avoid row locks"); 1563 RowLock rowLock1 = region.getRowLock(Bytes.toBytes("row_2")); 1564 RowLock rowLock2 = region.getRowLock(Bytes.toBytes("row_1")); 1565 RowLock rowLock3 = region.getRowLock(Bytes.toBytes("row_3")); 1566 RowLock rowLock4 = region.getRowLock(Bytes.toBytes("row_3"), true); 1567 1568 MultithreadedTestUtil.TestContext ctx = new MultithreadedTestUtil.TestContext(CONF); 1569 final AtomicReference<OperationStatus[]> retFromThread = new AtomicReference<>(); 1570 final CountDownLatch startingPuts = new CountDownLatch(1); 1571 final CountDownLatch startingClose = new CountDownLatch(1); 1572 TestThread putter = new TestThread(ctx) { 1573 @Override 1574 public void doWork() throws IOException { 1575 startingPuts.countDown(); 1576 retFromThread.set(region.batchMutate(puts)); 1577 } 1578 }; 1579 LOG.info("...starting put thread while holding locks"); 1580 ctx.addThread(putter); 1581 ctx.startThreads(); 1582 1583 // Now attempt to close the region from another thread. Prior to HBASE-12565 1584 // this would cause the in-progress batchMutate operation to to fail with 1585 // exception because it use to release and re-acquire the close-guard lock 1586 // between batches. Caller then didn't get status indicating which writes succeeded. 1587 // We now expect this thread to block until the batchMutate call finishes. 1588 Thread regionCloseThread = new TestThread(ctx) { 1589 @Override 1590 public void doWork() { 1591 try { 1592 startingPuts.await(); 1593 // Give some time for the batch mutate to get in. 1594 // We don't want to race with the mutate 1595 Thread.sleep(10); 1596 startingClose.countDown(); 1597 HBaseTestingUtility.closeRegionAndWAL(region); 1598 } catch (IOException e) { 1599 throw new RuntimeException(e); 1600 } catch (InterruptedException e) { 1601 throw new RuntimeException(e); 1602 } 1603 } 1604 }; 1605 regionCloseThread.start(); 1606 1607 startingClose.await(); 1608 startingPuts.await(); 1609 Thread.sleep(100); 1610 LOG.info("...releasing row lock 1, which should let put thread continue"); 1611 rowLock1.release(); 1612 rowLock2.release(); 1613 rowLock3.release(); 1614 waitForCounter(source, "syncTimeNumOps", syncs + 1); 1615 1616 LOG.info("...joining on put thread"); 1617 ctx.stop(); 1618 regionCloseThread.join(); 1619 1620 OperationStatus[] codes = retFromThread.get(); 1621 for (int i = 0; i < codes.length; i++) { 1622 assertEquals((i == 5) ? OperationStatusCode.BAD_FAMILY : OperationStatusCode.SUCCESS, 1623 codes[i].getOperationStatusCode()); 1624 } 1625 rowLock4.release(); 1626 } finally { 1627 HBaseTestingUtility.closeRegionAndWAL(this.region); 1628 this.region = null; 1629 } 1630 } 1631 1632 private void waitForCounter(MetricsWALSource source, String metricName, long expectedCount) 1633 throws InterruptedException { 1634 long startWait = System.currentTimeMillis(); 1635 long currentCount; 1636 while ((currentCount = metricsAssertHelper.getCounter(metricName, source)) < expectedCount) { 1637 Thread.sleep(100); 1638 if (System.currentTimeMillis() - startWait > 10000) { 1639 fail(String.format("Timed out waiting for '%s' >= '%s', currentCount=%s", metricName, 1640 expectedCount, currentCount)); 1641 } 1642 } 1643 } 1644 1645 @Test 1646 public void testAtomicBatchPut() throws IOException { 1647 final Put[] puts = new Put[10]; 1648 MetricsWALSource source = CompatibilitySingletonFactory.getInstance(MetricsWALSource.class); 1649 try { 1650 long syncs = prepareRegionForBachPut(puts, source, false); 1651 1652 // 1. Straight forward case, should succeed 1653 MutationBatchOperation batchOp = new MutationBatchOperation(region, puts, true, 1654 HConstants.NO_NONCE, HConstants.NO_NONCE); 1655 OperationStatus[] codes = this.region.batchMutate(batchOp); 1656 assertEquals(10, codes.length); 1657 for (int i = 0; i < 10; i++) { 1658 assertEquals(OperationStatusCode.SUCCESS, codes[i].getOperationStatusCode()); 1659 } 1660 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs + 1, source); 1661 1662 // 2. Failed to get lock 1663 RowLock lock = region.getRowLock(Bytes.toBytes("row_" + 3)); 1664 // Method {@link HRegion#getRowLock(byte[])} is reentrant. As 'row_3' is locked in this 1665 // thread, need to run {@link HRegion#batchMutate(HRegion.BatchOperation)} in different thread 1666 MultithreadedTestUtil.TestContext ctx = new MultithreadedTestUtil.TestContext(CONF); 1667 final AtomicReference<IOException> retFromThread = new AtomicReference<>(); 1668 final CountDownLatch finishedPuts = new CountDownLatch(1); 1669 final MutationBatchOperation finalBatchOp = new MutationBatchOperation(region, puts, true, 1670 HConstants 1671 .NO_NONCE, 1672 HConstants.NO_NONCE); 1673 TestThread putter = new TestThread(ctx) { 1674 @Override 1675 public void doWork() throws IOException { 1676 try { 1677 region.batchMutate(finalBatchOp); 1678 } catch (IOException ioe) { 1679 LOG.error("test failed!", ioe); 1680 retFromThread.set(ioe); 1681 } 1682 finishedPuts.countDown(); 1683 } 1684 }; 1685 LOG.info("...starting put thread while holding locks"); 1686 ctx.addThread(putter); 1687 ctx.startThreads(); 1688 LOG.info("...waiting for batch puts while holding locks"); 1689 try { 1690 finishedPuts.await(); 1691 } catch (InterruptedException e) { 1692 LOG.error("Interrupted!", e); 1693 } finally { 1694 if (lock != null) { 1695 lock.release(); 1696 } 1697 } 1698 assertNotNull(retFromThread.get()); 1699 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs + 1, source); 1700 1701 // 3. Exception thrown in validation 1702 LOG.info("Next a batch put with one invalid family"); 1703 puts[5].addColumn(Bytes.toBytes("BAD_CF"), qual, value); 1704 batchOp = new MutationBatchOperation(region, puts, true, HConstants.NO_NONCE, 1705 HConstants.NO_NONCE); 1706 thrown.expect(NoSuchColumnFamilyException.class); 1707 this.region.batchMutate(batchOp); 1708 } finally { 1709 HBaseTestingUtility.closeRegionAndWAL(this.region); 1710 this.region = null; 1711 } 1712 } 1713 1714 @Test 1715 public void testBatchPutWithTsSlop() throws Exception { 1716 // add data with a timestamp that is too recent for range. Ensure assert 1717 CONF.setInt("hbase.hregion.keyvalue.timestamp.slop.millisecs", 1000); 1718 final Put[] puts = new Put[10]; 1719 MetricsWALSource source = CompatibilitySingletonFactory.getInstance(MetricsWALSource.class); 1720 1721 try { 1722 long syncs = prepareRegionForBachPut(puts, source, true); 1723 1724 OperationStatus[] codes = this.region.batchMutate(puts); 1725 assertEquals(10, codes.length); 1726 for (int i = 0; i < 10; i++) { 1727 assertEquals(OperationStatusCode.SANITY_CHECK_FAILURE, codes[i].getOperationStatusCode()); 1728 } 1729 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs, source); 1730 } finally { 1731 HBaseTestingUtility.closeRegionAndWAL(this.region); 1732 this.region = null; 1733 } 1734 } 1735 1736 /** 1737 * @return syncs initial syncTimeNumOps 1738 */ 1739 private long prepareRegionForBachPut(final Put[] puts, final MetricsWALSource source, 1740 boolean slop) throws IOException { 1741 this.region = initHRegion(tableName, method, CONF, COLUMN_FAMILY_BYTES); 1742 1743 LOG.info("First a batch put with all valid puts"); 1744 for (int i = 0; i < puts.length; i++) { 1745 puts[i] = slop ? new Put(Bytes.toBytes("row_" + i), Long.MAX_VALUE - 100) : 1746 new Put(Bytes.toBytes("row_" + i)); 1747 puts[i].addColumn(COLUMN_FAMILY_BYTES, qual, value); 1748 } 1749 1750 long syncs = metricsAssertHelper.getCounter("syncTimeNumOps", source); 1751 metricsAssertHelper.assertCounter("syncTimeNumOps", syncs, source); 1752 return syncs; 1753 } 1754 1755 // //////////////////////////////////////////////////////////////////////////// 1756 // checkAndMutate tests 1757 // //////////////////////////////////////////////////////////////////////////// 1758 @Test 1759 public void testCheckAndMutate_WithEmptyRowValue() throws IOException { 1760 byte[] row1 = Bytes.toBytes("row1"); 1761 byte[] fam1 = Bytes.toBytes("fam1"); 1762 byte[] qf1 = Bytes.toBytes("qualifier"); 1763 byte[] emptyVal = new byte[] {}; 1764 byte[] val1 = Bytes.toBytes("value1"); 1765 byte[] val2 = Bytes.toBytes("value2"); 1766 1767 // Setting up region 1768 this.region = initHRegion(tableName, method, CONF, fam1); 1769 try { 1770 // Putting empty data in key 1771 Put put = new Put(row1); 1772 put.addColumn(fam1, qf1, emptyVal); 1773 1774 // checkAndPut with empty value 1775 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator( 1776 emptyVal), put); 1777 assertTrue(res); 1778 1779 // Putting data in key 1780 put = new Put(row1); 1781 put.addColumn(fam1, qf1, val1); 1782 1783 // checkAndPut with correct value 1784 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(emptyVal), 1785 put); 1786 assertTrue(res); 1787 1788 // not empty anymore 1789 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(emptyVal), 1790 put); 1791 assertFalse(res); 1792 1793 Delete delete = new Delete(row1); 1794 delete.addColumn(fam1, qf1); 1795 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(emptyVal), 1796 delete); 1797 assertFalse(res); 1798 1799 put = new Put(row1); 1800 put.addColumn(fam1, qf1, val2); 1801 // checkAndPut with correct value 1802 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val1), 1803 put); 1804 assertTrue(res); 1805 1806 // checkAndDelete with correct value 1807 delete = new Delete(row1); 1808 delete.addColumn(fam1, qf1); 1809 delete.addColumn(fam1, qf1); 1810 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val2), 1811 delete); 1812 assertTrue(res); 1813 1814 delete = new Delete(row1); 1815 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(emptyVal), 1816 delete); 1817 assertTrue(res); 1818 1819 // checkAndPut looking for a null value 1820 put = new Put(row1); 1821 put.addColumn(fam1, qf1, val1); 1822 1823 res = region 1824 .checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new NullComparator(), put); 1825 assertTrue(res); 1826 } finally { 1827 HBaseTestingUtility.closeRegionAndWAL(this.region); 1828 this.region = null; 1829 } 1830 } 1831 1832 @Test 1833 public void testCheckAndMutate_WithWrongValue() throws IOException { 1834 byte[] row1 = Bytes.toBytes("row1"); 1835 byte[] fam1 = Bytes.toBytes("fam1"); 1836 byte[] qf1 = Bytes.toBytes("qualifier"); 1837 byte[] val1 = Bytes.toBytes("value1"); 1838 byte[] val2 = Bytes.toBytes("value2"); 1839 BigDecimal bd1 = new BigDecimal(Double.MAX_VALUE); 1840 BigDecimal bd2 = new BigDecimal(Double.MIN_VALUE); 1841 1842 // Setting up region 1843 this.region = initHRegion(tableName, method, CONF, fam1); 1844 try { 1845 // Putting data in key 1846 Put put = new Put(row1); 1847 put.addColumn(fam1, qf1, val1); 1848 region.put(put); 1849 1850 // checkAndPut with wrong value 1851 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator( 1852 val2), put); 1853 assertEquals(false, res); 1854 1855 // checkAndDelete with wrong value 1856 Delete delete = new Delete(row1); 1857 delete.addFamily(fam1); 1858 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val2), 1859 put); 1860 assertEquals(false, res); 1861 1862 // Putting data in key 1863 put = new Put(row1); 1864 put.addColumn(fam1, qf1, Bytes.toBytes(bd1)); 1865 region.put(put); 1866 1867 // checkAndPut with wrong value 1868 res = 1869 region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator( 1870 bd2), put); 1871 assertEquals(false, res); 1872 1873 // checkAndDelete with wrong value 1874 delete = new Delete(row1); 1875 delete.addFamily(fam1); 1876 res = 1877 region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator( 1878 bd2), put); 1879 assertEquals(false, res); 1880 } finally { 1881 HBaseTestingUtility.closeRegionAndWAL(this.region); 1882 this.region = null; 1883 } 1884 } 1885 1886 @Test 1887 public void testCheckAndMutate_WithCorrectValue() throws IOException { 1888 byte[] row1 = Bytes.toBytes("row1"); 1889 byte[] fam1 = Bytes.toBytes("fam1"); 1890 byte[] qf1 = Bytes.toBytes("qualifier"); 1891 byte[] val1 = Bytes.toBytes("value1"); 1892 BigDecimal bd1 = new BigDecimal(Double.MIN_VALUE); 1893 1894 // Setting up region 1895 this.region = initHRegion(tableName, method, CONF, fam1); 1896 try { 1897 // Putting data in key 1898 Put put = new Put(row1); 1899 put.addColumn(fam1, qf1, val1); 1900 region.put(put); 1901 1902 // checkAndPut with correct value 1903 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator( 1904 val1), put); 1905 assertEquals(true, res); 1906 1907 // checkAndDelete with correct value 1908 Delete delete = new Delete(row1); 1909 delete.addColumn(fam1, qf1); 1910 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val1), 1911 delete); 1912 assertEquals(true, res); 1913 1914 // Putting data in key 1915 put = new Put(row1); 1916 put.addColumn(fam1, qf1, Bytes.toBytes(bd1)); 1917 region.put(put); 1918 1919 // checkAndPut with correct value 1920 res = 1921 region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator( 1922 bd1), put); 1923 assertEquals(true, res); 1924 1925 // checkAndDelete with correct value 1926 delete = new Delete(row1); 1927 delete.addColumn(fam1, qf1); 1928 res = 1929 region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BigDecimalComparator( 1930 bd1), delete); 1931 assertEquals(true, res); 1932 } finally { 1933 HBaseTestingUtility.closeRegionAndWAL(this.region); 1934 this.region = null; 1935 } 1936 } 1937 1938 @Test 1939 public void testCheckAndMutate_WithNonEqualCompareOp() throws IOException { 1940 byte[] row1 = Bytes.toBytes("row1"); 1941 byte[] fam1 = Bytes.toBytes("fam1"); 1942 byte[] qf1 = Bytes.toBytes("qualifier"); 1943 byte[] val1 = Bytes.toBytes("value1"); 1944 byte[] val2 = Bytes.toBytes("value2"); 1945 byte[] val3 = Bytes.toBytes("value3"); 1946 byte[] val4 = Bytes.toBytes("value4"); 1947 1948 // Setting up region 1949 this.region = initHRegion(tableName, method, CONF, fam1); 1950 try { 1951 // Putting val3 in key 1952 Put put = new Put(row1); 1953 put.addColumn(fam1, qf1, val3); 1954 region.put(put); 1955 1956 // Test CompareOp.LESS: original = val3, compare with val3, fail 1957 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS, 1958 new BinaryComparator(val3), put); 1959 assertEquals(false, res); 1960 1961 // Test CompareOp.LESS: original = val3, compare with val4, fail 1962 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS, 1963 new BinaryComparator(val4), put); 1964 assertEquals(false, res); 1965 1966 // Test CompareOp.LESS: original = val3, compare with val2, 1967 // succeed (now value = val2) 1968 put = new Put(row1); 1969 put.addColumn(fam1, qf1, val2); 1970 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS, 1971 new BinaryComparator(val2), put); 1972 assertEquals(true, res); 1973 1974 // Test CompareOp.LESS_OR_EQUAL: original = val2, compare with val3, fail 1975 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS_OR_EQUAL, 1976 new BinaryComparator(val3), put); 1977 assertEquals(false, res); 1978 1979 // Test CompareOp.LESS_OR_EQUAL: original = val2, compare with val2, 1980 // succeed (value still = val2) 1981 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS_OR_EQUAL, 1982 new BinaryComparator(val2), put); 1983 assertEquals(true, res); 1984 1985 // Test CompareOp.LESS_OR_EQUAL: original = val2, compare with val1, 1986 // succeed (now value = val3) 1987 put = new Put(row1); 1988 put.addColumn(fam1, qf1, val3); 1989 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.LESS_OR_EQUAL, 1990 new BinaryComparator(val1), put); 1991 assertEquals(true, res); 1992 1993 // Test CompareOp.GREATER: original = val3, compare with val3, fail 1994 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER, 1995 new BinaryComparator(val3), put); 1996 assertEquals(false, res); 1997 1998 // Test CompareOp.GREATER: original = val3, compare with val2, fail 1999 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER, 2000 new BinaryComparator(val2), put); 2001 assertEquals(false, res); 2002 2003 // Test CompareOp.GREATER: original = val3, compare with val4, 2004 // succeed (now value = val2) 2005 put = new Put(row1); 2006 put.addColumn(fam1, qf1, val2); 2007 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER, 2008 new BinaryComparator(val4), put); 2009 assertEquals(true, res); 2010 2011 // Test CompareOp.GREATER_OR_EQUAL: original = val2, compare with val1, fail 2012 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER_OR_EQUAL, 2013 new BinaryComparator(val1), put); 2014 assertEquals(false, res); 2015 2016 // Test CompareOp.GREATER_OR_EQUAL: original = val2, compare with val2, 2017 // succeed (value still = val2) 2018 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER_OR_EQUAL, 2019 new BinaryComparator(val2), put); 2020 assertEquals(true, res); 2021 2022 // Test CompareOp.GREATER_OR_EQUAL: original = val2, compare with val3, succeed 2023 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.GREATER_OR_EQUAL, 2024 new BinaryComparator(val3), put); 2025 assertEquals(true, res); 2026 } finally { 2027 HBaseTestingUtility.closeRegionAndWAL(this.region); 2028 this.region = null; 2029 } 2030 } 2031 2032 @Test 2033 public void testCheckAndPut_ThatPutWasWritten() throws IOException { 2034 byte[] row1 = Bytes.toBytes("row1"); 2035 byte[] fam1 = Bytes.toBytes("fam1"); 2036 byte[] fam2 = Bytes.toBytes("fam2"); 2037 byte[] qf1 = Bytes.toBytes("qualifier"); 2038 byte[] val1 = Bytes.toBytes("value1"); 2039 byte[] val2 = Bytes.toBytes("value2"); 2040 2041 byte[][] families = { fam1, fam2 }; 2042 2043 // Setting up region 2044 this.region = initHRegion(tableName, method, CONF, families); 2045 try { 2046 // Putting data in the key to check 2047 Put put = new Put(row1); 2048 put.addColumn(fam1, qf1, val1); 2049 region.put(put); 2050 2051 // Creating put to add 2052 long ts = System.currentTimeMillis(); 2053 KeyValue kv = new KeyValue(row1, fam2, qf1, ts, KeyValue.Type.Put, val2); 2054 put = new Put(row1); 2055 put.add(kv); 2056 2057 // checkAndPut with wrong value 2058 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator( 2059 val1), put); 2060 assertEquals(true, res); 2061 2062 Get get = new Get(row1); 2063 get.addColumn(fam2, qf1); 2064 Cell[] actual = region.get(get).rawCells(); 2065 2066 Cell[] expected = { kv }; 2067 2068 assertEquals(expected.length, actual.length); 2069 for (int i = 0; i < actual.length; i++) { 2070 assertEquals(expected[i], actual[i]); 2071 } 2072 } finally { 2073 HBaseTestingUtility.closeRegionAndWAL(this.region); 2074 this.region = null; 2075 } 2076 } 2077 2078 @Test 2079 public void testCheckAndPut_wrongRowInPut() throws IOException { 2080 this.region = initHRegion(tableName, method, CONF, COLUMNS); 2081 try { 2082 Put put = new Put(row2); 2083 put.addColumn(fam1, qual1, value1); 2084 try { 2085 region.checkAndMutate(row, fam1, qual1, CompareOperator.EQUAL, 2086 new BinaryComparator(value2), put); 2087 fail(); 2088 } catch (org.apache.hadoop.hbase.DoNotRetryIOException expected) { 2089 // expected exception. 2090 } 2091 } finally { 2092 HBaseTestingUtility.closeRegionAndWAL(this.region); 2093 this.region = null; 2094 } 2095 } 2096 2097 @Test 2098 public void testCheckAndDelete_ThatDeleteWasWritten() throws IOException { 2099 byte[] row1 = Bytes.toBytes("row1"); 2100 byte[] fam1 = Bytes.toBytes("fam1"); 2101 byte[] fam2 = Bytes.toBytes("fam2"); 2102 byte[] qf1 = Bytes.toBytes("qualifier1"); 2103 byte[] qf2 = Bytes.toBytes("qualifier2"); 2104 byte[] qf3 = Bytes.toBytes("qualifier3"); 2105 byte[] val1 = Bytes.toBytes("value1"); 2106 byte[] val2 = Bytes.toBytes("value2"); 2107 byte[] val3 = Bytes.toBytes("value3"); 2108 byte[] emptyVal = new byte[] {}; 2109 2110 byte[][] families = { fam1, fam2 }; 2111 2112 // Setting up region 2113 this.region = initHRegion(tableName, method, CONF, families); 2114 try { 2115 // Put content 2116 Put put = new Put(row1); 2117 put.addColumn(fam1, qf1, val1); 2118 region.put(put); 2119 Threads.sleep(2); 2120 2121 put = new Put(row1); 2122 put.addColumn(fam1, qf1, val2); 2123 put.addColumn(fam2, qf1, val3); 2124 put.addColumn(fam2, qf2, val2); 2125 put.addColumn(fam2, qf3, val1); 2126 put.addColumn(fam1, qf3, val1); 2127 region.put(put); 2128 2129 // Multi-column delete 2130 Delete delete = new Delete(row1); 2131 delete.addColumn(fam1, qf1); 2132 delete.addColumn(fam2, qf1); 2133 delete.addColumn(fam1, qf3); 2134 boolean res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator( 2135 val2), delete); 2136 assertEquals(true, res); 2137 2138 Get get = new Get(row1); 2139 get.addColumn(fam1, qf1); 2140 get.addColumn(fam1, qf3); 2141 get.addColumn(fam2, qf2); 2142 Result r = region.get(get); 2143 assertEquals(2, r.size()); 2144 assertArrayEquals(val1, r.getValue(fam1, qf1)); 2145 assertArrayEquals(val2, r.getValue(fam2, qf2)); 2146 2147 // Family delete 2148 delete = new Delete(row1); 2149 delete.addFamily(fam2); 2150 res = region.checkAndMutate(row1, fam2, qf1, CompareOperator.EQUAL, new BinaryComparator(emptyVal), 2151 delete); 2152 assertEquals(true, res); 2153 2154 get = new Get(row1); 2155 r = region.get(get); 2156 assertEquals(1, r.size()); 2157 assertArrayEquals(val1, r.getValue(fam1, qf1)); 2158 2159 // Row delete 2160 delete = new Delete(row1); 2161 res = region.checkAndMutate(row1, fam1, qf1, CompareOperator.EQUAL, new BinaryComparator(val1), 2162 delete); 2163 assertEquals(true, res); 2164 get = new Get(row1); 2165 r = region.get(get); 2166 assertEquals(0, r.size()); 2167 } finally { 2168 HBaseTestingUtility.closeRegionAndWAL(this.region); 2169 this.region = null; 2170 } 2171 } 2172 2173 // //////////////////////////////////////////////////////////////////////////// 2174 // Delete tests 2175 // //////////////////////////////////////////////////////////////////////////// 2176 @Test 2177 public void testDelete_multiDeleteColumn() throws IOException { 2178 byte[] row1 = Bytes.toBytes("row1"); 2179 byte[] fam1 = Bytes.toBytes("fam1"); 2180 byte[] qual = Bytes.toBytes("qualifier"); 2181 byte[] value = Bytes.toBytes("value"); 2182 2183 Put put = new Put(row1); 2184 put.addColumn(fam1, qual, 1, value); 2185 put.addColumn(fam1, qual, 2, value); 2186 2187 this.region = initHRegion(tableName, method, CONF, fam1); 2188 try { 2189 region.put(put); 2190 2191 // We do support deleting more than 1 'latest' version 2192 Delete delete = new Delete(row1); 2193 delete.addColumn(fam1, qual); 2194 delete.addColumn(fam1, qual); 2195 region.delete(delete); 2196 2197 Get get = new Get(row1); 2198 get.addFamily(fam1); 2199 Result r = region.get(get); 2200 assertEquals(0, r.size()); 2201 } finally { 2202 HBaseTestingUtility.closeRegionAndWAL(this.region); 2203 this.region = null; 2204 } 2205 } 2206 2207 @Test 2208 public void testDelete_CheckFamily() throws IOException { 2209 byte[] row1 = Bytes.toBytes("row1"); 2210 byte[] fam1 = Bytes.toBytes("fam1"); 2211 byte[] fam2 = Bytes.toBytes("fam2"); 2212 byte[] fam3 = Bytes.toBytes("fam3"); 2213 byte[] fam4 = Bytes.toBytes("fam4"); 2214 2215 // Setting up region 2216 this.region = initHRegion(tableName, method, CONF, fam1, fam2, fam3); 2217 try { 2218 List<Cell> kvs = new ArrayList<>(); 2219 kvs.add(new KeyValue(row1, fam4, null, null)); 2220 2221 // testing existing family 2222 byte[] family = fam2; 2223 try { 2224 NavigableMap<byte[], List<Cell>> deleteMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 2225 deleteMap.put(family, kvs); 2226 region.delete(deleteMap, Durability.SYNC_WAL); 2227 } catch (Exception e) { 2228 fail("Family " + new String(family, StandardCharsets.UTF_8) + " does not exist"); 2229 } 2230 2231 // testing non existing family 2232 boolean ok = false; 2233 family = fam4; 2234 try { 2235 NavigableMap<byte[], List<Cell>> deleteMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 2236 deleteMap.put(family, kvs); 2237 region.delete(deleteMap, Durability.SYNC_WAL); 2238 } catch (Exception e) { 2239 ok = true; 2240 } 2241 assertTrue("Family " + new String(family, StandardCharsets.UTF_8) + " does exist", ok); 2242 } finally { 2243 HBaseTestingUtility.closeRegionAndWAL(this.region); 2244 this.region = null; 2245 } 2246 } 2247 2248 @Test 2249 public void testDelete_mixed() throws IOException, InterruptedException { 2250 byte[] fam = Bytes.toBytes("info"); 2251 byte[][] families = { fam }; 2252 this.region = initHRegion(tableName, method, CONF, families); 2253 try { 2254 EnvironmentEdgeManagerTestHelper.injectEdge(new IncrementingEnvironmentEdge()); 2255 2256 byte[] row = Bytes.toBytes("table_name"); 2257 // column names 2258 byte[] serverinfo = Bytes.toBytes("serverinfo"); 2259 byte[] splitA = Bytes.toBytes("splitA"); 2260 byte[] splitB = Bytes.toBytes("splitB"); 2261 2262 // add some data: 2263 Put put = new Put(row); 2264 put.addColumn(fam, splitA, Bytes.toBytes("reference_A")); 2265 region.put(put); 2266 2267 put = new Put(row); 2268 put.addColumn(fam, splitB, Bytes.toBytes("reference_B")); 2269 region.put(put); 2270 2271 put = new Put(row); 2272 put.addColumn(fam, serverinfo, Bytes.toBytes("ip_address")); 2273 region.put(put); 2274 2275 // ok now delete a split: 2276 Delete delete = new Delete(row); 2277 delete.addColumns(fam, splitA); 2278 region.delete(delete); 2279 2280 // assert some things: 2281 Get get = new Get(row).addColumn(fam, serverinfo); 2282 Result result = region.get(get); 2283 assertEquals(1, result.size()); 2284 2285 get = new Get(row).addColumn(fam, splitA); 2286 result = region.get(get); 2287 assertEquals(0, result.size()); 2288 2289 get = new Get(row).addColumn(fam, splitB); 2290 result = region.get(get); 2291 assertEquals(1, result.size()); 2292 2293 // Assert that after a delete, I can put. 2294 put = new Put(row); 2295 put.addColumn(fam, splitA, Bytes.toBytes("reference_A")); 2296 region.put(put); 2297 get = new Get(row); 2298 result = region.get(get); 2299 assertEquals(3, result.size()); 2300 2301 // Now delete all... then test I can add stuff back 2302 delete = new Delete(row); 2303 region.delete(delete); 2304 assertEquals(0, region.get(get).size()); 2305 2306 region.put(new Put(row).addColumn(fam, splitA, Bytes.toBytes("reference_A"))); 2307 result = region.get(get); 2308 assertEquals(1, result.size()); 2309 } finally { 2310 HBaseTestingUtility.closeRegionAndWAL(this.region); 2311 this.region = null; 2312 } 2313 } 2314 2315 @Test 2316 public void testDeleteRowWithFutureTs() throws IOException { 2317 byte[] fam = Bytes.toBytes("info"); 2318 byte[][] families = { fam }; 2319 this.region = initHRegion(tableName, method, CONF, families); 2320 try { 2321 byte[] row = Bytes.toBytes("table_name"); 2322 // column names 2323 byte[] serverinfo = Bytes.toBytes("serverinfo"); 2324 2325 // add data in the far future 2326 Put put = new Put(row); 2327 put.addColumn(fam, serverinfo, HConstants.LATEST_TIMESTAMP - 5, Bytes.toBytes("value")); 2328 region.put(put); 2329 2330 // now delete something in the present 2331 Delete delete = new Delete(row); 2332 region.delete(delete); 2333 2334 // make sure we still see our data 2335 Get get = new Get(row).addColumn(fam, serverinfo); 2336 Result result = region.get(get); 2337 assertEquals(1, result.size()); 2338 2339 // delete the future row 2340 delete = new Delete(row, HConstants.LATEST_TIMESTAMP - 3); 2341 region.delete(delete); 2342 2343 // make sure it is gone 2344 get = new Get(row).addColumn(fam, serverinfo); 2345 result = region.get(get); 2346 assertEquals(0, result.size()); 2347 } finally { 2348 HBaseTestingUtility.closeRegionAndWAL(this.region); 2349 this.region = null; 2350 } 2351 } 2352 2353 /** 2354 * Tests that the special LATEST_TIMESTAMP option for puts gets replaced by 2355 * the actual timestamp 2356 */ 2357 @Test 2358 public void testPutWithLatestTS() throws IOException { 2359 byte[] fam = Bytes.toBytes("info"); 2360 byte[][] families = { fam }; 2361 this.region = initHRegion(tableName, method, CONF, families); 2362 try { 2363 byte[] row = Bytes.toBytes("row1"); 2364 // column names 2365 byte[] qual = Bytes.toBytes("qual"); 2366 2367 // add data with LATEST_TIMESTAMP, put without WAL 2368 Put put = new Put(row); 2369 put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, Bytes.toBytes("value")); 2370 region.put(put); 2371 2372 // Make sure it shows up with an actual timestamp 2373 Get get = new Get(row).addColumn(fam, qual); 2374 Result result = region.get(get); 2375 assertEquals(1, result.size()); 2376 Cell kv = result.rawCells()[0]; 2377 LOG.info("Got: " + kv); 2378 assertTrue("LATEST_TIMESTAMP was not replaced with real timestamp", 2379 kv.getTimestamp() != HConstants.LATEST_TIMESTAMP); 2380 2381 // Check same with WAL enabled (historically these took different 2382 // code paths, so check both) 2383 row = Bytes.toBytes("row2"); 2384 put = new Put(row); 2385 put.addColumn(fam, qual, HConstants.LATEST_TIMESTAMP, Bytes.toBytes("value")); 2386 region.put(put); 2387 2388 // Make sure it shows up with an actual timestamp 2389 get = new Get(row).addColumn(fam, qual); 2390 result = region.get(get); 2391 assertEquals(1, result.size()); 2392 kv = result.rawCells()[0]; 2393 LOG.info("Got: " + kv); 2394 assertTrue("LATEST_TIMESTAMP was not replaced with real timestamp", 2395 kv.getTimestamp() != HConstants.LATEST_TIMESTAMP); 2396 } finally { 2397 HBaseTestingUtility.closeRegionAndWAL(this.region); 2398 this.region = null; 2399 } 2400 2401 } 2402 2403 /** 2404 * Tests that there is server-side filtering for invalid timestamp upper 2405 * bound. Note that the timestamp lower bound is automatically handled for us 2406 * by the TTL field. 2407 */ 2408 @Test 2409 public void testPutWithTsSlop() throws IOException { 2410 byte[] fam = Bytes.toBytes("info"); 2411 byte[][] families = { fam }; 2412 2413 // add data with a timestamp that is too recent for range. Ensure assert 2414 CONF.setInt("hbase.hregion.keyvalue.timestamp.slop.millisecs", 1000); 2415 this.region = initHRegion(tableName, method, CONF, families); 2416 boolean caughtExcep = false; 2417 try { 2418 try { 2419 // no TS specified == use latest. should not error 2420 region.put(new Put(row).addColumn(fam, Bytes.toBytes("qual"), Bytes.toBytes("value"))); 2421 // TS out of range. should error 2422 region.put(new Put(row).addColumn(fam, Bytes.toBytes("qual"), 2423 System.currentTimeMillis() + 2000, Bytes.toBytes("value"))); 2424 fail("Expected IOE for TS out of configured timerange"); 2425 } catch (FailedSanityCheckException ioe) { 2426 LOG.debug("Received expected exception", ioe); 2427 caughtExcep = true; 2428 } 2429 assertTrue("Should catch FailedSanityCheckException", caughtExcep); 2430 } finally { 2431 HBaseTestingUtility.closeRegionAndWAL(this.region); 2432 this.region = null; 2433 } 2434 } 2435 2436 @Test 2437 public void testScanner_DeleteOneFamilyNotAnother() throws IOException { 2438 byte[] fam1 = Bytes.toBytes("columnA"); 2439 byte[] fam2 = Bytes.toBytes("columnB"); 2440 this.region = initHRegion(tableName, method, CONF, fam1, fam2); 2441 try { 2442 byte[] rowA = Bytes.toBytes("rowA"); 2443 byte[] rowB = Bytes.toBytes("rowB"); 2444 2445 byte[] value = Bytes.toBytes("value"); 2446 2447 Delete delete = new Delete(rowA); 2448 delete.addFamily(fam1); 2449 2450 region.delete(delete); 2451 2452 // now create data. 2453 Put put = new Put(rowA); 2454 put.addColumn(fam2, null, value); 2455 region.put(put); 2456 2457 put = new Put(rowB); 2458 put.addColumn(fam1, null, value); 2459 put.addColumn(fam2, null, value); 2460 region.put(put); 2461 2462 Scan scan = new Scan(); 2463 scan.addFamily(fam1).addFamily(fam2); 2464 InternalScanner s = region.getScanner(scan); 2465 List<Cell> results = new ArrayList<>(); 2466 s.next(results); 2467 assertTrue(CellUtil.matchingRows(results.get(0), rowA)); 2468 2469 results.clear(); 2470 s.next(results); 2471 assertTrue(CellUtil.matchingRows(results.get(0), rowB)); 2472 } finally { 2473 HBaseTestingUtility.closeRegionAndWAL(this.region); 2474 this.region = null; 2475 } 2476 } 2477 2478 @Test 2479 public void testDataInMemoryWithoutWAL() throws IOException { 2480 FileSystem fs = FileSystem.get(CONF); 2481 Path rootDir = new Path(dir + "testDataInMemoryWithoutWAL"); 2482 FSHLog hLog = new FSHLog(fs, rootDir, "testDataInMemoryWithoutWAL", CONF); 2483 // This chunk creation is done throughout the code base. Do we want to move it into core? 2484 // It is missing from this test. W/o it we NPE. 2485 ChunkCreator.initialize(MemStoreLABImpl.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null); 2486 HRegion region = initHRegion(tableName, null, null, false, Durability.SYNC_WAL, hLog, 2487 COLUMN_FAMILY_BYTES); 2488 2489 Cell originalCell = CellUtil.createCell(row, COLUMN_FAMILY_BYTES, qual1, 2490 System.currentTimeMillis(), KeyValue.Type.Put.getCode(), value1); 2491 final long originalSize = KeyValueUtil.length(originalCell); 2492 2493 Cell addCell = CellUtil.createCell(row, COLUMN_FAMILY_BYTES, qual1, 2494 System.currentTimeMillis(), KeyValue.Type.Put.getCode(), Bytes.toBytes("xxxxxxxxxx")); 2495 final long addSize = KeyValueUtil.length(addCell); 2496 2497 LOG.info("originalSize:" + originalSize 2498 + ", addSize:" + addSize); 2499 // start test. We expect that the addPut's durability will be replaced 2500 // by originalPut's durability. 2501 2502 // case 1: 2503 testDataInMemoryWithoutWAL(region, 2504 new Put(row).add(originalCell).setDurability(Durability.SKIP_WAL), 2505 new Put(row).add(addCell).setDurability(Durability.SKIP_WAL), 2506 originalSize + addSize); 2507 2508 // case 2: 2509 testDataInMemoryWithoutWAL(region, 2510 new Put(row).add(originalCell).setDurability(Durability.SKIP_WAL), 2511 new Put(row).add(addCell).setDurability(Durability.SYNC_WAL), 2512 originalSize + addSize); 2513 2514 // case 3: 2515 testDataInMemoryWithoutWAL(region, 2516 new Put(row).add(originalCell).setDurability(Durability.SYNC_WAL), 2517 new Put(row).add(addCell).setDurability(Durability.SKIP_WAL), 2518 0); 2519 2520 // case 4: 2521 testDataInMemoryWithoutWAL(region, 2522 new Put(row).add(originalCell).setDurability(Durability.SYNC_WAL), 2523 new Put(row).add(addCell).setDurability(Durability.SYNC_WAL), 2524 0); 2525 } 2526 2527 private static void testDataInMemoryWithoutWAL(HRegion region, Put originalPut, 2528 final Put addPut, long delta) throws IOException { 2529 final long initSize = region.getDataInMemoryWithoutWAL(); 2530 // save normalCPHost and replaced by mockedCPHost 2531 RegionCoprocessorHost normalCPHost = region.getCoprocessorHost(); 2532 RegionCoprocessorHost mockedCPHost = Mockito.mock(RegionCoprocessorHost.class); 2533 // Because the preBatchMutate returns void, we can't do usual Mockito when...then form. Must 2534 // do below format (from Mockito doc). 2535 Mockito.doAnswer(new Answer() { 2536 @Override 2537 public Object answer(InvocationOnMock invocation) throws Throwable { 2538 MiniBatchOperationInProgress<Mutation> mb = invocation.getArgument(0); 2539 mb.addOperationsFromCP(0, new Mutation[]{addPut}); 2540 return null; 2541 } 2542 }).when(mockedCPHost).preBatchMutate(Mockito.isA(MiniBatchOperationInProgress.class)); 2543 region.setCoprocessorHost(mockedCPHost); 2544 region.put(originalPut); 2545 region.setCoprocessorHost(normalCPHost); 2546 final long finalSize = region.getDataInMemoryWithoutWAL(); 2547 assertEquals("finalSize:" + finalSize + ", initSize:" 2548 + initSize + ", delta:" + delta,finalSize, initSize + delta); 2549 } 2550 2551 @Test 2552 public void testDeleteColumns_PostInsert() throws IOException, InterruptedException { 2553 Delete delete = new Delete(row); 2554 delete.addColumns(fam1, qual1); 2555 doTestDelete_AndPostInsert(delete); 2556 } 2557 2558 @Test 2559 public void testaddFamily_PostInsert() throws IOException, InterruptedException { 2560 Delete delete = new Delete(row); 2561 delete.addFamily(fam1); 2562 doTestDelete_AndPostInsert(delete); 2563 } 2564 2565 public void doTestDelete_AndPostInsert(Delete delete) throws IOException, InterruptedException { 2566 this.region = initHRegion(tableName, method, CONF, fam1); 2567 try { 2568 EnvironmentEdgeManagerTestHelper.injectEdge(new IncrementingEnvironmentEdge()); 2569 Put put = new Put(row); 2570 put.addColumn(fam1, qual1, value1); 2571 region.put(put); 2572 2573 // now delete the value: 2574 region.delete(delete); 2575 2576 // ok put data: 2577 put = new Put(row); 2578 put.addColumn(fam1, qual1, value2); 2579 region.put(put); 2580 2581 // ok get: 2582 Get get = new Get(row); 2583 get.addColumn(fam1, qual1); 2584 2585 Result r = region.get(get); 2586 assertEquals(1, r.size()); 2587 assertArrayEquals(value2, r.getValue(fam1, qual1)); 2588 2589 // next: 2590 Scan scan = new Scan(row); 2591 scan.addColumn(fam1, qual1); 2592 InternalScanner s = region.getScanner(scan); 2593 2594 List<Cell> results = new ArrayList<>(); 2595 assertEquals(false, s.next(results)); 2596 assertEquals(1, results.size()); 2597 Cell kv = results.get(0); 2598 2599 assertArrayEquals(value2, CellUtil.cloneValue(kv)); 2600 assertArrayEquals(fam1, CellUtil.cloneFamily(kv)); 2601 assertArrayEquals(qual1, CellUtil.cloneQualifier(kv)); 2602 assertArrayEquals(row, CellUtil.cloneRow(kv)); 2603 } finally { 2604 HBaseTestingUtility.closeRegionAndWAL(this.region); 2605 this.region = null; 2606 } 2607 } 2608 2609 @Test 2610 public void testDelete_CheckTimestampUpdated() throws IOException { 2611 byte[] row1 = Bytes.toBytes("row1"); 2612 byte[] col1 = Bytes.toBytes("col1"); 2613 byte[] col2 = Bytes.toBytes("col2"); 2614 byte[] col3 = Bytes.toBytes("col3"); 2615 2616 // Setting up region 2617 this.region = initHRegion(tableName, method, CONF, fam1); 2618 try { 2619 // Building checkerList 2620 List<Cell> kvs = new ArrayList<>(); 2621 kvs.add(new KeyValue(row1, fam1, col1, null)); 2622 kvs.add(new KeyValue(row1, fam1, col2, null)); 2623 kvs.add(new KeyValue(row1, fam1, col3, null)); 2624 2625 NavigableMap<byte[], List<Cell>> deleteMap = new TreeMap<>(Bytes.BYTES_COMPARATOR); 2626 deleteMap.put(fam1, kvs); 2627 region.delete(deleteMap, Durability.SYNC_WAL); 2628 2629 // extract the key values out the memstore: 2630 // This is kinda hacky, but better than nothing... 2631 long now = System.currentTimeMillis(); 2632 AbstractMemStore memstore = (AbstractMemStore)region.getStore(fam1).memstore; 2633 Cell firstCell = memstore.getActive().first(); 2634 assertTrue(firstCell.getTimestamp() <= now); 2635 now = firstCell.getTimestamp(); 2636 for (Cell cell : memstore.getActive().getCellSet()) { 2637 assertTrue(cell.getTimestamp() <= now); 2638 now = cell.getTimestamp(); 2639 } 2640 } finally { 2641 HBaseTestingUtility.closeRegionAndWAL(this.region); 2642 this.region = null; 2643 } 2644 } 2645 2646 // //////////////////////////////////////////////////////////////////////////// 2647 // Get tests 2648 // //////////////////////////////////////////////////////////////////////////// 2649 @Test 2650 public void testGet_FamilyChecker() throws IOException { 2651 byte[] row1 = Bytes.toBytes("row1"); 2652 byte[] fam1 = Bytes.toBytes("fam1"); 2653 byte[] fam2 = Bytes.toBytes("False"); 2654 byte[] col1 = Bytes.toBytes("col1"); 2655 2656 // Setting up region 2657 this.region = initHRegion(tableName, method, CONF, fam1); 2658 try { 2659 Get get = new Get(row1); 2660 get.addColumn(fam2, col1); 2661 2662 // Test 2663 try { 2664 region.get(get); 2665 } catch (org.apache.hadoop.hbase.DoNotRetryIOException e) { 2666 assertFalse(false); 2667 return; 2668 } 2669 assertFalse(true); 2670 } finally { 2671 HBaseTestingUtility.closeRegionAndWAL(this.region); 2672 this.region = null; 2673 } 2674 } 2675 2676 @Test 2677 public void testGet_Basic() throws IOException { 2678 byte[] row1 = Bytes.toBytes("row1"); 2679 byte[] fam1 = Bytes.toBytes("fam1"); 2680 byte[] col1 = Bytes.toBytes("col1"); 2681 byte[] col2 = Bytes.toBytes("col2"); 2682 byte[] col3 = Bytes.toBytes("col3"); 2683 byte[] col4 = Bytes.toBytes("col4"); 2684 byte[] col5 = Bytes.toBytes("col5"); 2685 2686 // Setting up region 2687 this.region = initHRegion(tableName, method, CONF, fam1); 2688 try { 2689 // Add to memstore 2690 Put put = new Put(row1); 2691 put.addColumn(fam1, col1, null); 2692 put.addColumn(fam1, col2, null); 2693 put.addColumn(fam1, col3, null); 2694 put.addColumn(fam1, col4, null); 2695 put.addColumn(fam1, col5, null); 2696 region.put(put); 2697 2698 Get get = new Get(row1); 2699 get.addColumn(fam1, col2); 2700 get.addColumn(fam1, col4); 2701 // Expected result 2702 KeyValue kv1 = new KeyValue(row1, fam1, col2); 2703 KeyValue kv2 = new KeyValue(row1, fam1, col4); 2704 KeyValue[] expected = { kv1, kv2 }; 2705 2706 // Test 2707 Result res = region.get(get); 2708 assertEquals(expected.length, res.size()); 2709 for (int i = 0; i < res.size(); i++) { 2710 assertTrue(CellUtil.matchingRows(expected[i], res.rawCells()[i])); 2711 assertTrue(CellUtil.matchingFamily(expected[i], res.rawCells()[i])); 2712 assertTrue(CellUtil.matchingQualifier(expected[i], res.rawCells()[i])); 2713 } 2714 2715 // Test using a filter on a Get 2716 Get g = new Get(row1); 2717 final int count = 2; 2718 g.setFilter(new ColumnCountGetFilter(count)); 2719 res = region.get(g); 2720 assertEquals(count, res.size()); 2721 } finally { 2722 HBaseTestingUtility.closeRegionAndWAL(this.region); 2723 this.region = null; 2724 } 2725 } 2726 2727 @Test 2728 public void testGet_Empty() throws IOException { 2729 byte[] row = Bytes.toBytes("row"); 2730 byte[] fam = Bytes.toBytes("fam"); 2731 2732 this.region = initHRegion(tableName, method, CONF, fam); 2733 try { 2734 Get get = new Get(row); 2735 get.addFamily(fam); 2736 Result r = region.get(get); 2737 2738 assertTrue(r.isEmpty()); 2739 } finally { 2740 HBaseTestingUtility.closeRegionAndWAL(this.region); 2741 this.region = null; 2742 } 2743 } 2744 2745 @Test 2746 public void testGetWithFilter() throws IOException, InterruptedException { 2747 byte[] row1 = Bytes.toBytes("row1"); 2748 byte[] fam1 = Bytes.toBytes("fam1"); 2749 byte[] col1 = Bytes.toBytes("col1"); 2750 byte[] value1 = Bytes.toBytes("value1"); 2751 byte[] value2 = Bytes.toBytes("value2"); 2752 2753 final int maxVersions = 3; 2754 HColumnDescriptor hcd = new HColumnDescriptor(fam1); 2755 hcd.setMaxVersions(maxVersions); 2756 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("testFilterAndColumnTracker")); 2757 htd.addFamily(hcd); 2758 ChunkCreator.initialize(MemStoreLABImpl.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null); 2759 HRegionInfo info = new HRegionInfo(htd.getTableName(), null, null, false); 2760 Path logDir = TEST_UTIL.getDataTestDirOnTestFS(method + ".log"); 2761 final WAL wal = HBaseTestingUtility.createWal(TEST_UTIL.getConfiguration(), logDir, info); 2762 this.region = TEST_UTIL.createLocalHRegion(info, htd, wal); 2763 2764 try { 2765 // Put 4 version to memstore 2766 long ts = 0; 2767 Put put = new Put(row1, ts); 2768 put.addColumn(fam1, col1, value1); 2769 region.put(put); 2770 put = new Put(row1, ts + 1); 2771 put.addColumn(fam1, col1, Bytes.toBytes("filter1")); 2772 region.put(put); 2773 put = new Put(row1, ts + 2); 2774 put.addColumn(fam1, col1, Bytes.toBytes("filter2")); 2775 region.put(put); 2776 put = new Put(row1, ts + 3); 2777 put.addColumn(fam1, col1, value2); 2778 region.put(put); 2779 2780 Get get = new Get(row1); 2781 get.setMaxVersions(); 2782 Result res = region.get(get); 2783 // Get 3 versions, the oldest version has gone from user view 2784 assertEquals(maxVersions, res.size()); 2785 2786 get.setFilter(new ValueFilter(CompareOp.EQUAL, new SubstringComparator("value"))); 2787 res = region.get(get); 2788 // When use value filter, the oldest version should still gone from user view and it 2789 // should only return one key vaule 2790 assertEquals(1, res.size()); 2791 assertTrue(CellUtil.matchingValue(new KeyValue(row1, fam1, col1, value2), res.rawCells()[0])); 2792 assertEquals(ts + 3, res.rawCells()[0].getTimestamp()); 2793 2794 region.flush(true); 2795 region.compact(true); 2796 Thread.sleep(1000); 2797 res = region.get(get); 2798 // After flush and compact, the result should be consistent with previous result 2799 assertEquals(1, res.size()); 2800 assertTrue(CellUtil.matchingValue(new KeyValue(row1, fam1, col1, value2), res.rawCells()[0])); 2801 } finally { 2802 HBaseTestingUtility.closeRegionAndWAL(this.region); 2803 this.region = null; 2804 } 2805 } 2806 2807 // //////////////////////////////////////////////////////////////////////////// 2808 // Scanner tests 2809 // //////////////////////////////////////////////////////////////////////////// 2810 @Test 2811 public void testGetScanner_WithOkFamilies() throws IOException { 2812 byte[] fam1 = Bytes.toBytes("fam1"); 2813 byte[] fam2 = Bytes.toBytes("fam2"); 2814 2815 byte[][] families = { fam1, fam2 }; 2816 2817 // Setting up region 2818 this.region = initHRegion(tableName, method, CONF, families); 2819 try { 2820 Scan scan = new Scan(); 2821 scan.addFamily(fam1); 2822 scan.addFamily(fam2); 2823 try { 2824 region.getScanner(scan); 2825 } catch (Exception e) { 2826 assertTrue("Families could not be found in Region", false); 2827 } 2828 } finally { 2829 HBaseTestingUtility.closeRegionAndWAL(this.region); 2830 this.region = null; 2831 } 2832 } 2833 2834 @Test 2835 public void testGetScanner_WithNotOkFamilies() throws IOException { 2836 byte[] fam1 = Bytes.toBytes("fam1"); 2837 byte[] fam2 = Bytes.toBytes("fam2"); 2838 2839 byte[][] families = { fam1 }; 2840 2841 // Setting up region 2842 this.region = initHRegion(tableName, method, CONF, families); 2843 try { 2844 Scan scan = new Scan(); 2845 scan.addFamily(fam2); 2846 boolean ok = false; 2847 try { 2848 region.getScanner(scan); 2849 } catch (Exception e) { 2850 ok = true; 2851 } 2852 assertTrue("Families could not be found in Region", ok); 2853 } finally { 2854 HBaseTestingUtility.closeRegionAndWAL(this.region); 2855 this.region = null; 2856 } 2857 } 2858 2859 @Test 2860 public void testGetScanner_WithNoFamilies() throws IOException { 2861 byte[] row1 = Bytes.toBytes("row1"); 2862 byte[] fam1 = Bytes.toBytes("fam1"); 2863 byte[] fam2 = Bytes.toBytes("fam2"); 2864 byte[] fam3 = Bytes.toBytes("fam3"); 2865 byte[] fam4 = Bytes.toBytes("fam4"); 2866 2867 byte[][] families = { fam1, fam2, fam3, fam4 }; 2868 2869 // Setting up region 2870 this.region = initHRegion(tableName, method, CONF, families); 2871 try { 2872 2873 // Putting data in Region 2874 Put put = new Put(row1); 2875 put.addColumn(fam1, null, null); 2876 put.addColumn(fam2, null, null); 2877 put.addColumn(fam3, null, null); 2878 put.addColumn(fam4, null, null); 2879 region.put(put); 2880 2881 Scan scan = null; 2882 HRegion.RegionScannerImpl is = null; 2883 2884 // Testing to see how many scanners that is produced by getScanner, 2885 // starting 2886 // with known number, 2 - current = 1 2887 scan = new Scan(); 2888 scan.addFamily(fam2); 2889 scan.addFamily(fam4); 2890 is = region.getScanner(scan); 2891 assertEquals(1, is.storeHeap.getHeap().size()); 2892 2893 scan = new Scan(); 2894 is = region.getScanner(scan); 2895 assertEquals(families.length - 1, is.storeHeap.getHeap().size()); 2896 } finally { 2897 HBaseTestingUtility.closeRegionAndWAL(this.region); 2898 this.region = null; 2899 } 2900 } 2901 2902 /** 2903 * This method tests https://issues.apache.org/jira/browse/HBASE-2516. 2904 * 2905 * @throws IOException 2906 */ 2907 @Test 2908 public void testGetScanner_WithRegionClosed() throws IOException { 2909 byte[] fam1 = Bytes.toBytes("fam1"); 2910 byte[] fam2 = Bytes.toBytes("fam2"); 2911 2912 byte[][] families = { fam1, fam2 }; 2913 2914 // Setting up region 2915 try { 2916 this.region = initHRegion(tableName, method, CONF, families); 2917 } catch (IOException e) { 2918 e.printStackTrace(); 2919 fail("Got IOException during initHRegion, " + e.getMessage()); 2920 } 2921 try { 2922 region.closed.set(true); 2923 try { 2924 region.getScanner(null); 2925 fail("Expected to get an exception during getScanner on a region that is closed"); 2926 } catch (NotServingRegionException e) { 2927 // this is the correct exception that is expected 2928 } catch (IOException e) { 2929 fail("Got wrong type of exception - should be a NotServingRegionException, " + 2930 "but was an IOException: " 2931 + e.getMessage()); 2932 } 2933 } finally { 2934 HBaseTestingUtility.closeRegionAndWAL(this.region); 2935 this.region = null; 2936 } 2937 } 2938 2939 @Test 2940 public void testRegionScanner_Next() throws IOException { 2941 byte[] row1 = Bytes.toBytes("row1"); 2942 byte[] row2 = Bytes.toBytes("row2"); 2943 byte[] fam1 = Bytes.toBytes("fam1"); 2944 byte[] fam2 = Bytes.toBytes("fam2"); 2945 byte[] fam3 = Bytes.toBytes("fam3"); 2946 byte[] fam4 = Bytes.toBytes("fam4"); 2947 2948 byte[][] families = { fam1, fam2, fam3, fam4 }; 2949 long ts = System.currentTimeMillis(); 2950 2951 // Setting up region 2952 this.region = initHRegion(tableName, method, CONF, families); 2953 try { 2954 // Putting data in Region 2955 Put put = null; 2956 put = new Put(row1); 2957 put.addColumn(fam1, (byte[]) null, ts, null); 2958 put.addColumn(fam2, (byte[]) null, ts, null); 2959 put.addColumn(fam3, (byte[]) null, ts, null); 2960 put.addColumn(fam4, (byte[]) null, ts, null); 2961 region.put(put); 2962 2963 put = new Put(row2); 2964 put.addColumn(fam1, (byte[]) null, ts, null); 2965 put.addColumn(fam2, (byte[]) null, ts, null); 2966 put.addColumn(fam3, (byte[]) null, ts, null); 2967 put.addColumn(fam4, (byte[]) null, ts, null); 2968 region.put(put); 2969 2970 Scan scan = new Scan(); 2971 scan.addFamily(fam2); 2972 scan.addFamily(fam4); 2973 InternalScanner is = region.getScanner(scan); 2974 2975 List<Cell> res = null; 2976 2977 // Result 1 2978 List<Cell> expected1 = new ArrayList<>(); 2979 expected1.add(new KeyValue(row1, fam2, null, ts, KeyValue.Type.Put, null)); 2980 expected1.add(new KeyValue(row1, fam4, null, ts, KeyValue.Type.Put, null)); 2981 2982 res = new ArrayList<>(); 2983 is.next(res); 2984 for (int i = 0; i < res.size(); i++) { 2985 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected1.get(i), res.get(i))); 2986 } 2987 2988 // Result 2 2989 List<Cell> expected2 = new ArrayList<>(); 2990 expected2.add(new KeyValue(row2, fam2, null, ts, KeyValue.Type.Put, null)); 2991 expected2.add(new KeyValue(row2, fam4, null, ts, KeyValue.Type.Put, null)); 2992 2993 res = new ArrayList<>(); 2994 is.next(res); 2995 for (int i = 0; i < res.size(); i++) { 2996 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected2.get(i), res.get(i))); 2997 } 2998 } finally { 2999 HBaseTestingUtility.closeRegionAndWAL(this.region); 3000 this.region = null; 3001 } 3002 } 3003 3004 @Test 3005 public void testScanner_ExplicitColumns_FromMemStore_EnforceVersions() throws IOException { 3006 byte[] row1 = Bytes.toBytes("row1"); 3007 byte[] qf1 = Bytes.toBytes("qualifier1"); 3008 byte[] qf2 = Bytes.toBytes("qualifier2"); 3009 byte[] fam1 = Bytes.toBytes("fam1"); 3010 byte[][] families = { fam1 }; 3011 3012 long ts1 = System.currentTimeMillis(); 3013 long ts2 = ts1 + 1; 3014 long ts3 = ts1 + 2; 3015 3016 // Setting up region 3017 this.region = initHRegion(tableName, method, CONF, families); 3018 try { 3019 // Putting data in Region 3020 Put put = null; 3021 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3022 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3023 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3024 3025 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3026 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3027 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3028 3029 put = new Put(row1); 3030 put.add(kv13); 3031 put.add(kv12); 3032 put.add(kv11); 3033 put.add(kv23); 3034 put.add(kv22); 3035 put.add(kv21); 3036 region.put(put); 3037 3038 // Expected 3039 List<Cell> expected = new ArrayList<>(); 3040 expected.add(kv13); 3041 expected.add(kv12); 3042 3043 Scan scan = new Scan(row1); 3044 scan.addColumn(fam1, qf1); 3045 scan.setMaxVersions(MAX_VERSIONS); 3046 List<Cell> actual = new ArrayList<>(); 3047 InternalScanner scanner = region.getScanner(scan); 3048 3049 boolean hasNext = scanner.next(actual); 3050 assertEquals(false, hasNext); 3051 3052 // Verify result 3053 for (int i = 0; i < expected.size(); i++) { 3054 assertEquals(expected.get(i), actual.get(i)); 3055 } 3056 } finally { 3057 HBaseTestingUtility.closeRegionAndWAL(this.region); 3058 this.region = null; 3059 } 3060 } 3061 3062 @Test 3063 public void testScanner_ExplicitColumns_FromFilesOnly_EnforceVersions() throws IOException { 3064 byte[] row1 = Bytes.toBytes("row1"); 3065 byte[] qf1 = Bytes.toBytes("qualifier1"); 3066 byte[] qf2 = Bytes.toBytes("qualifier2"); 3067 byte[] fam1 = Bytes.toBytes("fam1"); 3068 byte[][] families = { fam1 }; 3069 3070 long ts1 = 1; // System.currentTimeMillis(); 3071 long ts2 = ts1 + 1; 3072 long ts3 = ts1 + 2; 3073 3074 // Setting up region 3075 this.region = initHRegion(tableName, method, CONF, families); 3076 try { 3077 // Putting data in Region 3078 Put put = null; 3079 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3080 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3081 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3082 3083 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3084 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3085 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3086 3087 put = new Put(row1); 3088 put.add(kv13); 3089 put.add(kv12); 3090 put.add(kv11); 3091 put.add(kv23); 3092 put.add(kv22); 3093 put.add(kv21); 3094 region.put(put); 3095 region.flush(true); 3096 3097 // Expected 3098 List<Cell> expected = new ArrayList<>(); 3099 expected.add(kv13); 3100 expected.add(kv12); 3101 expected.add(kv23); 3102 expected.add(kv22); 3103 3104 Scan scan = new Scan(row1); 3105 scan.addColumn(fam1, qf1); 3106 scan.addColumn(fam1, qf2); 3107 scan.setMaxVersions(MAX_VERSIONS); 3108 List<Cell> actual = new ArrayList<>(); 3109 InternalScanner scanner = region.getScanner(scan); 3110 3111 boolean hasNext = scanner.next(actual); 3112 assertEquals(false, hasNext); 3113 3114 // Verify result 3115 for (int i = 0; i < expected.size(); i++) { 3116 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected.get(i), actual.get(i))); 3117 } 3118 } finally { 3119 HBaseTestingUtility.closeRegionAndWAL(this.region); 3120 this.region = null; 3121 } 3122 } 3123 3124 @Test 3125 public void testScanner_ExplicitColumns_FromMemStoreAndFiles_EnforceVersions() throws 3126 IOException { 3127 byte[] row1 = Bytes.toBytes("row1"); 3128 byte[] fam1 = Bytes.toBytes("fam1"); 3129 byte[][] families = { fam1 }; 3130 byte[] qf1 = Bytes.toBytes("qualifier1"); 3131 byte[] qf2 = Bytes.toBytes("qualifier2"); 3132 3133 long ts1 = 1; 3134 long ts2 = ts1 + 1; 3135 long ts3 = ts1 + 2; 3136 long ts4 = ts1 + 3; 3137 3138 // Setting up region 3139 this.region = initHRegion(tableName, method, CONF, families); 3140 try { 3141 // Putting data in Region 3142 KeyValue kv14 = new KeyValue(row1, fam1, qf1, ts4, KeyValue.Type.Put, null); 3143 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3144 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3145 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3146 3147 KeyValue kv24 = new KeyValue(row1, fam1, qf2, ts4, KeyValue.Type.Put, null); 3148 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3149 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3150 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3151 3152 Put put = null; 3153 put = new Put(row1); 3154 put.add(kv14); 3155 put.add(kv24); 3156 region.put(put); 3157 region.flush(true); 3158 3159 put = new Put(row1); 3160 put.add(kv23); 3161 put.add(kv13); 3162 region.put(put); 3163 region.flush(true); 3164 3165 put = new Put(row1); 3166 put.add(kv22); 3167 put.add(kv12); 3168 region.put(put); 3169 region.flush(true); 3170 3171 put = new Put(row1); 3172 put.add(kv21); 3173 put.add(kv11); 3174 region.put(put); 3175 3176 // Expected 3177 List<Cell> expected = new ArrayList<>(); 3178 expected.add(kv14); 3179 expected.add(kv13); 3180 expected.add(kv12); 3181 expected.add(kv24); 3182 expected.add(kv23); 3183 expected.add(kv22); 3184 3185 Scan scan = new Scan(row1); 3186 scan.addColumn(fam1, qf1); 3187 scan.addColumn(fam1, qf2); 3188 int versions = 3; 3189 scan.setMaxVersions(versions); 3190 List<Cell> actual = new ArrayList<>(); 3191 InternalScanner scanner = region.getScanner(scan); 3192 3193 boolean hasNext = scanner.next(actual); 3194 assertEquals(false, hasNext); 3195 3196 // Verify result 3197 for (int i = 0; i < expected.size(); i++) { 3198 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected.get(i), actual.get(i))); 3199 } 3200 } finally { 3201 HBaseTestingUtility.closeRegionAndWAL(this.region); 3202 this.region = null; 3203 } 3204 } 3205 3206 @Test 3207 public void testScanner_Wildcard_FromMemStore_EnforceVersions() throws IOException { 3208 byte[] row1 = Bytes.toBytes("row1"); 3209 byte[] qf1 = Bytes.toBytes("qualifier1"); 3210 byte[] qf2 = Bytes.toBytes("qualifier2"); 3211 byte[] fam1 = Bytes.toBytes("fam1"); 3212 byte[][] families = { fam1 }; 3213 3214 long ts1 = System.currentTimeMillis(); 3215 long ts2 = ts1 + 1; 3216 long ts3 = ts1 + 2; 3217 3218 // Setting up region 3219 this.region = initHRegion(tableName, method, CONF, families); 3220 try { 3221 // Putting data in Region 3222 Put put = null; 3223 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3224 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3225 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3226 3227 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3228 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3229 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3230 3231 put = new Put(row1); 3232 put.add(kv13); 3233 put.add(kv12); 3234 put.add(kv11); 3235 put.add(kv23); 3236 put.add(kv22); 3237 put.add(kv21); 3238 region.put(put); 3239 3240 // Expected 3241 List<Cell> expected = new ArrayList<>(); 3242 expected.add(kv13); 3243 expected.add(kv12); 3244 expected.add(kv23); 3245 expected.add(kv22); 3246 3247 Scan scan = new Scan(row1); 3248 scan.addFamily(fam1); 3249 scan.setMaxVersions(MAX_VERSIONS); 3250 List<Cell> actual = new ArrayList<>(); 3251 InternalScanner scanner = region.getScanner(scan); 3252 3253 boolean hasNext = scanner.next(actual); 3254 assertEquals(false, hasNext); 3255 3256 // Verify result 3257 for (int i = 0; i < expected.size(); i++) { 3258 assertEquals(expected.get(i), actual.get(i)); 3259 } 3260 } finally { 3261 HBaseTestingUtility.closeRegionAndWAL(this.region); 3262 this.region = null; 3263 } 3264 } 3265 3266 @Test 3267 public void testScanner_Wildcard_FromFilesOnly_EnforceVersions() throws IOException { 3268 byte[] row1 = Bytes.toBytes("row1"); 3269 byte[] qf1 = Bytes.toBytes("qualifier1"); 3270 byte[] qf2 = Bytes.toBytes("qualifier2"); 3271 byte[] fam1 = Bytes.toBytes("fam1"); 3272 3273 long ts1 = 1; // System.currentTimeMillis(); 3274 long ts2 = ts1 + 1; 3275 long ts3 = ts1 + 2; 3276 3277 // Setting up region 3278 this.region = initHRegion(tableName, method, CONF, fam1); 3279 try { 3280 // Putting data in Region 3281 Put put = null; 3282 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3283 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3284 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3285 3286 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3287 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3288 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3289 3290 put = new Put(row1); 3291 put.add(kv13); 3292 put.add(kv12); 3293 put.add(kv11); 3294 put.add(kv23); 3295 put.add(kv22); 3296 put.add(kv21); 3297 region.put(put); 3298 region.flush(true); 3299 3300 // Expected 3301 List<Cell> expected = new ArrayList<>(); 3302 expected.add(kv13); 3303 expected.add(kv12); 3304 expected.add(kv23); 3305 expected.add(kv22); 3306 3307 Scan scan = new Scan(row1); 3308 scan.addFamily(fam1); 3309 scan.setMaxVersions(MAX_VERSIONS); 3310 List<Cell> actual = new ArrayList<>(); 3311 InternalScanner scanner = region.getScanner(scan); 3312 3313 boolean hasNext = scanner.next(actual); 3314 assertEquals(false, hasNext); 3315 3316 // Verify result 3317 for (int i = 0; i < expected.size(); i++) { 3318 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected.get(i), actual.get(i))); 3319 } 3320 } finally { 3321 HBaseTestingUtility.closeRegionAndWAL(this.region); 3322 this.region = null; 3323 } 3324 } 3325 3326 @Test 3327 public void testScanner_StopRow1542() throws IOException { 3328 byte[] family = Bytes.toBytes("testFamily"); 3329 this.region = initHRegion(tableName, method, CONF, family); 3330 try { 3331 byte[] row1 = Bytes.toBytes("row111"); 3332 byte[] row2 = Bytes.toBytes("row222"); 3333 byte[] row3 = Bytes.toBytes("row333"); 3334 byte[] row4 = Bytes.toBytes("row444"); 3335 byte[] row5 = Bytes.toBytes("row555"); 3336 3337 byte[] col1 = Bytes.toBytes("Pub111"); 3338 byte[] col2 = Bytes.toBytes("Pub222"); 3339 3340 Put put = new Put(row1); 3341 put.addColumn(family, col1, Bytes.toBytes(10L)); 3342 region.put(put); 3343 3344 put = new Put(row2); 3345 put.addColumn(family, col1, Bytes.toBytes(15L)); 3346 region.put(put); 3347 3348 put = new Put(row3); 3349 put.addColumn(family, col2, Bytes.toBytes(20L)); 3350 region.put(put); 3351 3352 put = new Put(row4); 3353 put.addColumn(family, col2, Bytes.toBytes(30L)); 3354 region.put(put); 3355 3356 put = new Put(row5); 3357 put.addColumn(family, col1, Bytes.toBytes(40L)); 3358 region.put(put); 3359 3360 Scan scan = new Scan(row3, row4); 3361 scan.setMaxVersions(); 3362 scan.addColumn(family, col1); 3363 InternalScanner s = region.getScanner(scan); 3364 3365 List<Cell> results = new ArrayList<>(); 3366 assertEquals(false, s.next(results)); 3367 assertEquals(0, results.size()); 3368 } finally { 3369 HBaseTestingUtility.closeRegionAndWAL(this.region); 3370 this.region = null; 3371 } 3372 } 3373 3374 @Test 3375 public void testScanner_Wildcard_FromMemStoreAndFiles_EnforceVersions() throws IOException { 3376 byte[] row1 = Bytes.toBytes("row1"); 3377 byte[] fam1 = Bytes.toBytes("fam1"); 3378 byte[] qf1 = Bytes.toBytes("qualifier1"); 3379 byte[] qf2 = Bytes.toBytes("quateslifier2"); 3380 3381 long ts1 = 1; 3382 long ts2 = ts1 + 1; 3383 long ts3 = ts1 + 2; 3384 long ts4 = ts1 + 3; 3385 3386 // Setting up region 3387 this.region = initHRegion(tableName, method, CONF, fam1); 3388 try { 3389 // Putting data in Region 3390 KeyValue kv14 = new KeyValue(row1, fam1, qf1, ts4, KeyValue.Type.Put, null); 3391 KeyValue kv13 = new KeyValue(row1, fam1, qf1, ts3, KeyValue.Type.Put, null); 3392 KeyValue kv12 = new KeyValue(row1, fam1, qf1, ts2, KeyValue.Type.Put, null); 3393 KeyValue kv11 = new KeyValue(row1, fam1, qf1, ts1, KeyValue.Type.Put, null); 3394 3395 KeyValue kv24 = new KeyValue(row1, fam1, qf2, ts4, KeyValue.Type.Put, null); 3396 KeyValue kv23 = new KeyValue(row1, fam1, qf2, ts3, KeyValue.Type.Put, null); 3397 KeyValue kv22 = new KeyValue(row1, fam1, qf2, ts2, KeyValue.Type.Put, null); 3398 KeyValue kv21 = new KeyValue(row1, fam1, qf2, ts1, KeyValue.Type.Put, null); 3399 3400 Put put = null; 3401 put = new Put(row1); 3402 put.add(kv14); 3403 put.add(kv24); 3404 region.put(put); 3405 region.flush(true); 3406 3407 put = new Put(row1); 3408 put.add(kv23); 3409 put.add(kv13); 3410 region.put(put); 3411 region.flush(true); 3412 3413 put = new Put(row1); 3414 put.add(kv22); 3415 put.add(kv12); 3416 region.put(put); 3417 region.flush(true); 3418 3419 put = new Put(row1); 3420 put.add(kv21); 3421 put.add(kv11); 3422 region.put(put); 3423 3424 // Expected 3425 List<KeyValue> expected = new ArrayList<>(); 3426 expected.add(kv14); 3427 expected.add(kv13); 3428 expected.add(kv12); 3429 expected.add(kv24); 3430 expected.add(kv23); 3431 expected.add(kv22); 3432 3433 Scan scan = new Scan(row1); 3434 int versions = 3; 3435 scan.setMaxVersions(versions); 3436 List<Cell> actual = new ArrayList<>(); 3437 InternalScanner scanner = region.getScanner(scan); 3438 3439 boolean hasNext = scanner.next(actual); 3440 assertEquals(false, hasNext); 3441 3442 // Verify result 3443 for (int i = 0; i < expected.size(); i++) { 3444 assertTrue(PrivateCellUtil.equalsIgnoreMvccVersion(expected.get(i), actual.get(i))); 3445 } 3446 } finally { 3447 HBaseTestingUtility.closeRegionAndWAL(this.region); 3448 this.region = null; 3449 } 3450 } 3451 3452 /** 3453 * Added for HBASE-5416 3454 * 3455 * Here we test scan optimization when only subset of CFs are used in filter 3456 * conditions. 3457 */ 3458 @Test 3459 public void testScanner_JoinedScanners() throws IOException { 3460 byte[] cf_essential = Bytes.toBytes("essential"); 3461 byte[] cf_joined = Bytes.toBytes("joined"); 3462 byte[] cf_alpha = Bytes.toBytes("alpha"); 3463 this.region = initHRegion(tableName, method, CONF, cf_essential, cf_joined, cf_alpha); 3464 try { 3465 byte[] row1 = Bytes.toBytes("row1"); 3466 byte[] row2 = Bytes.toBytes("row2"); 3467 byte[] row3 = Bytes.toBytes("row3"); 3468 3469 byte[] col_normal = Bytes.toBytes("d"); 3470 byte[] col_alpha = Bytes.toBytes("a"); 3471 3472 byte[] filtered_val = Bytes.toBytes(3); 3473 3474 Put put = new Put(row1); 3475 put.addColumn(cf_essential, col_normal, Bytes.toBytes(1)); 3476 put.addColumn(cf_joined, col_alpha, Bytes.toBytes(1)); 3477 region.put(put); 3478 3479 put = new Put(row2); 3480 put.addColumn(cf_essential, col_alpha, Bytes.toBytes(2)); 3481 put.addColumn(cf_joined, col_normal, Bytes.toBytes(2)); 3482 put.addColumn(cf_alpha, col_alpha, Bytes.toBytes(2)); 3483 region.put(put); 3484 3485 put = new Put(row3); 3486 put.addColumn(cf_essential, col_normal, filtered_val); 3487 put.addColumn(cf_joined, col_normal, filtered_val); 3488 region.put(put); 3489 3490 // Check two things: 3491 // 1. result list contains expected values 3492 // 2. result list is sorted properly 3493 3494 Scan scan = new Scan(); 3495 Filter filter = new SingleColumnValueExcludeFilter(cf_essential, col_normal, 3496 CompareOp.NOT_EQUAL, filtered_val); 3497 scan.setFilter(filter); 3498 scan.setLoadColumnFamiliesOnDemand(true); 3499 InternalScanner s = region.getScanner(scan); 3500 3501 List<Cell> results = new ArrayList<>(); 3502 assertTrue(s.next(results)); 3503 assertEquals(1, results.size()); 3504 results.clear(); 3505 3506 assertTrue(s.next(results)); 3507 assertEquals(3, results.size()); 3508 assertTrue("orderCheck", CellUtil.matchingFamily(results.get(0), cf_alpha)); 3509 assertTrue("orderCheck", CellUtil.matchingFamily(results.get(1), cf_essential)); 3510 assertTrue("orderCheck", CellUtil.matchingFamily(results.get(2), cf_joined)); 3511 results.clear(); 3512 3513 assertFalse(s.next(results)); 3514 assertEquals(0, results.size()); 3515 } finally { 3516 HBaseTestingUtility.closeRegionAndWAL(this.region); 3517 this.region = null; 3518 } 3519 } 3520 3521 /** 3522 * HBASE-5416 3523 * 3524 * Test case when scan limits amount of KVs returned on each next() call. 3525 */ 3526 @Test 3527 public void testScanner_JoinedScannersWithLimits() throws IOException { 3528 final byte[] cf_first = Bytes.toBytes("first"); 3529 final byte[] cf_second = Bytes.toBytes("second"); 3530 3531 this.region = initHRegion(tableName, method, CONF, cf_first, cf_second); 3532 try { 3533 final byte[] col_a = Bytes.toBytes("a"); 3534 final byte[] col_b = Bytes.toBytes("b"); 3535 3536 Put put; 3537 3538 for (int i = 0; i < 10; i++) { 3539 put = new Put(Bytes.toBytes("r" + Integer.toString(i))); 3540 put.addColumn(cf_first, col_a, Bytes.toBytes(i)); 3541 if (i < 5) { 3542 put.addColumn(cf_first, col_b, Bytes.toBytes(i)); 3543 put.addColumn(cf_second, col_a, Bytes.toBytes(i)); 3544 put.addColumn(cf_second, col_b, Bytes.toBytes(i)); 3545 } 3546 region.put(put); 3547 } 3548 3549 Scan scan = new Scan(); 3550 scan.setLoadColumnFamiliesOnDemand(true); 3551 Filter bogusFilter = new FilterBase() { 3552 @Override 3553 public ReturnCode filterCell(final Cell ignored) throws IOException { 3554 return ReturnCode.INCLUDE; 3555 } 3556 @Override 3557 public boolean isFamilyEssential(byte[] name) { 3558 return Bytes.equals(name, cf_first); 3559 } 3560 }; 3561 3562 scan.setFilter(bogusFilter); 3563 InternalScanner s = region.getScanner(scan); 3564 3565 // Our data looks like this: 3566 // r0: first:a, first:b, second:a, second:b 3567 // r1: first:a, first:b, second:a, second:b 3568 // r2: first:a, first:b, second:a, second:b 3569 // r3: first:a, first:b, second:a, second:b 3570 // r4: first:a, first:b, second:a, second:b 3571 // r5: first:a 3572 // r6: first:a 3573 // r7: first:a 3574 // r8: first:a 3575 // r9: first:a 3576 3577 // But due to next's limit set to 3, we should get this: 3578 // r0: first:a, first:b, second:a 3579 // r0: second:b 3580 // r1: first:a, first:b, second:a 3581 // r1: second:b 3582 // r2: first:a, first:b, second:a 3583 // r2: second:b 3584 // r3: first:a, first:b, second:a 3585 // r3: second:b 3586 // r4: first:a, first:b, second:a 3587 // r4: second:b 3588 // r5: first:a 3589 // r6: first:a 3590 // r7: first:a 3591 // r8: first:a 3592 // r9: first:a 3593 3594 List<Cell> results = new ArrayList<>(); 3595 int index = 0; 3596 ScannerContext scannerContext = ScannerContext.newBuilder().setBatchLimit(3).build(); 3597 while (true) { 3598 boolean more = s.next(results, scannerContext); 3599 if ((index >> 1) < 5) { 3600 if (index % 2 == 0) { 3601 assertEquals(3, results.size()); 3602 } else { 3603 assertEquals(1, results.size()); 3604 } 3605 } else { 3606 assertEquals(1, results.size()); 3607 } 3608 results.clear(); 3609 index++; 3610 if (!more) { 3611 break; 3612 } 3613 } 3614 } finally { 3615 HBaseTestingUtility.closeRegionAndWAL(this.region); 3616 this.region = null; 3617 } 3618 } 3619 3620 /** 3621 * Write an HFile block full with Cells whose qualifier that are identical between 3622 * 0 and Short.MAX_VALUE. See HBASE-13329. 3623 * @throws Exception 3624 */ 3625 @Test 3626 public void testLongQualifier() throws Exception { 3627 byte[] family = Bytes.toBytes("family"); 3628 this.region = initHRegion(tableName, method, CONF, family); 3629 byte[] q = new byte[Short.MAX_VALUE+2]; 3630 Arrays.fill(q, 0, q.length-1, (byte)42); 3631 for (byte i=0; i<10; i++) { 3632 Put p = new Put(Bytes.toBytes("row")); 3633 // qualifiers that differ past Short.MAX_VALUE 3634 q[q.length-1]=i; 3635 p.addColumn(family, q, q); 3636 region.put(p); 3637 } 3638 region.flush(false); 3639 HBaseTestingUtility.closeRegionAndWAL(this.region); 3640 this.region = null; 3641 } 3642 3643 /** 3644 * Flushes the cache in a thread while scanning. The tests verify that the 3645 * scan is coherent - e.g. the returned results are always of the same or 3646 * later update as the previous results. 3647 * 3648 * @throws IOException 3649 * scan / compact 3650 * @throws InterruptedException 3651 * thread join 3652 */ 3653 @Test 3654 public void testFlushCacheWhileScanning() throws IOException, InterruptedException { 3655 byte[] family = Bytes.toBytes("family"); 3656 int numRows = 1000; 3657 int flushAndScanInterval = 10; 3658 int compactInterval = 10 * flushAndScanInterval; 3659 3660 this.region = initHRegion(tableName, method, CONF, family); 3661 FlushThread flushThread = new FlushThread(); 3662 try { 3663 flushThread.start(); 3664 3665 Scan scan = new Scan(); 3666 scan.addFamily(family); 3667 scan.setFilter(new SingleColumnValueFilter(family, qual1, CompareOp.EQUAL, 3668 new BinaryComparator(Bytes.toBytes(5L)))); 3669 3670 int expectedCount = 0; 3671 List<Cell> res = new ArrayList<>(); 3672 3673 boolean toggle = true; 3674 for (long i = 0; i < numRows; i++) { 3675 Put put = new Put(Bytes.toBytes(i)); 3676 put.setDurability(Durability.SKIP_WAL); 3677 put.addColumn(family, qual1, Bytes.toBytes(i % 10)); 3678 region.put(put); 3679 3680 if (i != 0 && i % compactInterval == 0) { 3681 LOG.debug("iteration = " + i+ " ts="+System.currentTimeMillis()); 3682 region.compact(true); 3683 } 3684 3685 if (i % 10 == 5L) { 3686 expectedCount++; 3687 } 3688 3689 if (i != 0 && i % flushAndScanInterval == 0) { 3690 res.clear(); 3691 InternalScanner scanner = region.getScanner(scan); 3692 if (toggle) { 3693 flushThread.flush(); 3694 } 3695 while (scanner.next(res)) 3696 ; 3697 if (!toggle) { 3698 flushThread.flush(); 3699 } 3700 assertEquals("toggle="+toggle+"i=" + i + " ts="+System.currentTimeMillis(), 3701 expectedCount, res.size()); 3702 toggle = !toggle; 3703 } 3704 } 3705 3706 } finally { 3707 try { 3708 flushThread.done(); 3709 flushThread.join(); 3710 flushThread.checkNoError(); 3711 } catch (InterruptedException ie) { 3712 LOG.warn("Caught exception when joining with flushThread", ie); 3713 } 3714 HBaseTestingUtility.closeRegionAndWAL(this.region); 3715 this.region = null; 3716 } 3717 } 3718 3719 protected class FlushThread extends Thread { 3720 private volatile boolean done; 3721 private Throwable error = null; 3722 3723 FlushThread() { 3724 super("FlushThread"); 3725 } 3726 3727 public void done() { 3728 done = true; 3729 synchronized (this) { 3730 interrupt(); 3731 } 3732 } 3733 3734 public void checkNoError() { 3735 if (error != null) { 3736 assertNull(error); 3737 } 3738 } 3739 3740 @Override 3741 public void run() { 3742 done = false; 3743 while (!done) { 3744 synchronized (this) { 3745 try { 3746 wait(); 3747 } catch (InterruptedException ignored) { 3748 if (done) { 3749 break; 3750 } 3751 } 3752 } 3753 try { 3754 region.flush(true); 3755 } catch (IOException e) { 3756 if (!done) { 3757 LOG.error("Error while flushing cache", e); 3758 error = e; 3759 } 3760 break; 3761 } catch (Throwable t) { 3762 LOG.error("Uncaught exception", t); 3763 throw t; 3764 } 3765 } 3766 } 3767 3768 public void flush() { 3769 synchronized (this) { 3770 notify(); 3771 } 3772 } 3773 } 3774 3775 /** 3776 * Writes very wide records and scans for the latest every time.. Flushes and 3777 * compacts the region every now and then to keep things realistic. 3778 * 3779 * @throws IOException 3780 * by flush / scan / compaction 3781 * @throws InterruptedException 3782 * when joining threads 3783 */ 3784 @Test 3785 public void testWritesWhileScanning() throws IOException, InterruptedException { 3786 int testCount = 100; 3787 int numRows = 1; 3788 int numFamilies = 10; 3789 int numQualifiers = 100; 3790 int flushInterval = 7; 3791 int compactInterval = 5 * flushInterval; 3792 byte[][] families = new byte[numFamilies][]; 3793 for (int i = 0; i < numFamilies; i++) { 3794 families[i] = Bytes.toBytes("family" + i); 3795 } 3796 byte[][] qualifiers = new byte[numQualifiers][]; 3797 for (int i = 0; i < numQualifiers; i++) { 3798 qualifiers[i] = Bytes.toBytes("qual" + i); 3799 } 3800 3801 this.region = initHRegion(tableName, method, CONF, families); 3802 FlushThread flushThread = new FlushThread(); 3803 PutThread putThread = new PutThread(numRows, families, qualifiers); 3804 try { 3805 putThread.start(); 3806 putThread.waitForFirstPut(); 3807 3808 flushThread.start(); 3809 3810 Scan scan = new Scan(Bytes.toBytes("row0"), Bytes.toBytes("row1")); 3811 3812 int expectedCount = numFamilies * numQualifiers; 3813 List<Cell> res = new ArrayList<>(); 3814 3815 long prevTimestamp = 0L; 3816 for (int i = 0; i < testCount; i++) { 3817 3818 if (i != 0 && i % compactInterval == 0) { 3819 region.compact(true); 3820 for (HStore store : region.getStores()) { 3821 store.closeAndArchiveCompactedFiles(); 3822 } 3823 } 3824 3825 if (i != 0 && i % flushInterval == 0) { 3826 flushThread.flush(); 3827 } 3828 3829 boolean previousEmpty = res.isEmpty(); 3830 res.clear(); 3831 InternalScanner scanner = region.getScanner(scan); 3832 while (scanner.next(res)) 3833 ; 3834 if (!res.isEmpty() || !previousEmpty || i > compactInterval) { 3835 assertEquals("i=" + i, expectedCount, res.size()); 3836 long timestamp = res.get(0).getTimestamp(); 3837 assertTrue("Timestamps were broke: " + timestamp + " prev: " + prevTimestamp, 3838 timestamp >= prevTimestamp); 3839 prevTimestamp = timestamp; 3840 } 3841 } 3842 3843 putThread.done(); 3844 3845 region.flush(true); 3846 3847 } finally { 3848 try { 3849 flushThread.done(); 3850 flushThread.join(); 3851 flushThread.checkNoError(); 3852 3853 putThread.join(); 3854 putThread.checkNoError(); 3855 } catch (InterruptedException ie) { 3856 LOG.warn("Caught exception when joining with flushThread", ie); 3857 } 3858 3859 try { 3860 HBaseTestingUtility.closeRegionAndWAL(this.region); 3861 } catch (DroppedSnapshotException dse) { 3862 // We could get this on way out because we interrupt the background flusher and it could 3863 // fail anywhere causing a DSE over in the background flusher... only it is not properly 3864 // dealt with so could still be memory hanging out when we get to here -- memory we can't 3865 // flush because the accounting is 'off' since original DSE. 3866 } 3867 this.region = null; 3868 } 3869 } 3870 3871 protected class PutThread extends Thread { 3872 private volatile boolean done; 3873 private volatile int numPutsFinished = 0; 3874 3875 private Throwable error = null; 3876 private int numRows; 3877 private byte[][] families; 3878 private byte[][] qualifiers; 3879 3880 private PutThread(int numRows, byte[][] families, byte[][] qualifiers) { 3881 super("PutThread"); 3882 this.numRows = numRows; 3883 this.families = families; 3884 this.qualifiers = qualifiers; 3885 } 3886 3887 /** 3888 * Block calling thread until this instance of PutThread has put at least one row. 3889 */ 3890 public void waitForFirstPut() throws InterruptedException { 3891 // wait until put thread actually puts some data 3892 while (isAlive() && numPutsFinished == 0) { 3893 checkNoError(); 3894 Thread.sleep(50); 3895 } 3896 } 3897 3898 public void done() { 3899 done = true; 3900 synchronized (this) { 3901 interrupt(); 3902 } 3903 } 3904 3905 public void checkNoError() { 3906 if (error != null) { 3907 assertNull(error); 3908 } 3909 } 3910 3911 @Override 3912 public void run() { 3913 done = false; 3914 while (!done) { 3915 try { 3916 for (int r = 0; r < numRows; r++) { 3917 byte[] row = Bytes.toBytes("row" + r); 3918 Put put = new Put(row); 3919 put.setDurability(Durability.SKIP_WAL); 3920 byte[] value = Bytes.toBytes(String.valueOf(numPutsFinished)); 3921 for (byte[] family : families) { 3922 for (byte[] qualifier : qualifiers) { 3923 put.addColumn(family, qualifier, numPutsFinished, value); 3924 } 3925 } 3926 region.put(put); 3927 numPutsFinished++; 3928 if (numPutsFinished > 0 && numPutsFinished % 47 == 0) { 3929 System.out.println("put iteration = " + numPutsFinished); 3930 Delete delete = new Delete(row, (long) numPutsFinished - 30); 3931 region.delete(delete); 3932 } 3933 numPutsFinished++; 3934 } 3935 } catch (InterruptedIOException e) { 3936 // This is fine. It means we are done, or didn't get the lock on time 3937 LOG.info("Interrupted", e); 3938 } catch (IOException e) { 3939 LOG.error("Error while putting records", e); 3940 error = e; 3941 break; 3942 } 3943 } 3944 3945 } 3946 3947 } 3948 3949 /** 3950 * Writes very wide records and gets the latest row every time.. Flushes and 3951 * compacts the region aggressivly to catch issues. 3952 * 3953 * @throws IOException 3954 * by flush / scan / compaction 3955 * @throws InterruptedException 3956 * when joining threads 3957 */ 3958 @Test 3959 public void testWritesWhileGetting() throws Exception { 3960 int testCount = 50; 3961 int numRows = 1; 3962 int numFamilies = 10; 3963 int numQualifiers = 100; 3964 int compactInterval = 100; 3965 byte[][] families = new byte[numFamilies][]; 3966 for (int i = 0; i < numFamilies; i++) { 3967 families[i] = Bytes.toBytes("family" + i); 3968 } 3969 byte[][] qualifiers = new byte[numQualifiers][]; 3970 for (int i = 0; i < numQualifiers; i++) { 3971 qualifiers[i] = Bytes.toBytes("qual" + i); 3972 } 3973 3974 3975 // This test flushes constantly and can cause many files to be created, 3976 // possibly 3977 // extending over the ulimit. Make sure compactions are aggressive in 3978 // reducing 3979 // the number of HFiles created. 3980 Configuration conf = HBaseConfiguration.create(CONF); 3981 conf.setInt("hbase.hstore.compaction.min", 1); 3982 conf.setInt("hbase.hstore.compaction.max", 1000); 3983 this.region = initHRegion(tableName, method, conf, families); 3984 PutThread putThread = null; 3985 MultithreadedTestUtil.TestContext ctx = new MultithreadedTestUtil.TestContext(conf); 3986 try { 3987 putThread = new PutThread(numRows, families, qualifiers); 3988 putThread.start(); 3989 putThread.waitForFirstPut(); 3990 3991 // Add a thread that flushes as fast as possible 3992 ctx.addThread(new RepeatingTestThread(ctx) { 3993 3994 @Override 3995 public void doAnAction() throws Exception { 3996 region.flush(true); 3997 // Compact regularly to avoid creating too many files and exceeding 3998 // the ulimit. 3999 region.compact(false); 4000 for (HStore store : region.getStores()) { 4001 store.closeAndArchiveCompactedFiles(); 4002 } 4003 } 4004 }); 4005 ctx.startThreads(); 4006 4007 Get get = new Get(Bytes.toBytes("row0")); 4008 Result result = null; 4009 4010 int expectedCount = numFamilies * numQualifiers; 4011 4012 long prevTimestamp = 0L; 4013 for (int i = 0; i < testCount; i++) { 4014 LOG.info("testWritesWhileGetting verify turn " + i); 4015 boolean previousEmpty = result == null || result.isEmpty(); 4016 result = region.get(get); 4017 if (!result.isEmpty() || !previousEmpty || i > compactInterval) { 4018 assertEquals("i=" + i, expectedCount, result.size()); 4019 // TODO this was removed, now what dangit?! 4020 // search looking for the qualifier in question? 4021 long timestamp = 0; 4022 for (Cell kv : result.rawCells()) { 4023 if (CellUtil.matchingFamily(kv, families[0]) 4024 && CellUtil.matchingQualifier(kv, qualifiers[0])) { 4025 timestamp = kv.getTimestamp(); 4026 } 4027 } 4028 assertTrue(timestamp >= prevTimestamp); 4029 prevTimestamp = timestamp; 4030 Cell previousKV = null; 4031 4032 for (Cell kv : result.rawCells()) { 4033 byte[] thisValue = CellUtil.cloneValue(kv); 4034 if (previousKV != null) { 4035 if (Bytes.compareTo(CellUtil.cloneValue(previousKV), thisValue) != 0) { 4036 LOG.warn("These two KV should have the same value." + " Previous KV:" + previousKV 4037 + "(memStoreTS:" + previousKV.getSequenceId() + ")" + ", New KV: " + kv 4038 + "(memStoreTS:" + kv.getSequenceId() + ")"); 4039 assertEquals(0, Bytes.compareTo(CellUtil.cloneValue(previousKV), thisValue)); 4040 } 4041 } 4042 previousKV = kv; 4043 } 4044 } 4045 } 4046 } finally { 4047 if (putThread != null) 4048 putThread.done(); 4049 4050 region.flush(true); 4051 4052 if (putThread != null) { 4053 putThread.join(); 4054 putThread.checkNoError(); 4055 } 4056 4057 ctx.stop(); 4058 HBaseTestingUtility.closeRegionAndWAL(this.region); 4059 this.region = null; 4060 } 4061 } 4062 4063 @Test 4064 public void testHolesInMeta() throws Exception { 4065 byte[] family = Bytes.toBytes("family"); 4066 this.region = initHRegion(tableName, Bytes.toBytes("x"), Bytes.toBytes("z"), method, CONF, 4067 false, family); 4068 try { 4069 byte[] rowNotServed = Bytes.toBytes("a"); 4070 Get g = new Get(rowNotServed); 4071 try { 4072 region.get(g); 4073 fail(); 4074 } catch (WrongRegionException x) { 4075 // OK 4076 } 4077 byte[] row = Bytes.toBytes("y"); 4078 g = new Get(row); 4079 region.get(g); 4080 } finally { 4081 HBaseTestingUtility.closeRegionAndWAL(this.region); 4082 this.region = null; 4083 } 4084 } 4085 4086 @Test 4087 public void testIndexesScanWithOneDeletedRow() throws IOException { 4088 byte[] family = Bytes.toBytes("family"); 4089 4090 // Setting up region 4091 this.region = initHRegion(tableName, method, CONF, family); 4092 try { 4093 Put put = new Put(Bytes.toBytes(1L)); 4094 put.addColumn(family, qual1, 1L, Bytes.toBytes(1L)); 4095 region.put(put); 4096 4097 region.flush(true); 4098 4099 Delete delete = new Delete(Bytes.toBytes(1L), 1L); 4100 region.delete(delete); 4101 4102 put = new Put(Bytes.toBytes(2L)); 4103 put.addColumn(family, qual1, 2L, Bytes.toBytes(2L)); 4104 region.put(put); 4105 4106 Scan idxScan = new Scan(); 4107 idxScan.addFamily(family); 4108 idxScan.setFilter(new FilterList(FilterList.Operator.MUST_PASS_ALL, Arrays.<Filter> asList( 4109 new SingleColumnValueFilter(family, qual1, CompareOp.GREATER_OR_EQUAL, 4110 new BinaryComparator(Bytes.toBytes(0L))), new SingleColumnValueFilter(family, qual1, 4111 CompareOp.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes(3L)))))); 4112 InternalScanner scanner = region.getScanner(idxScan); 4113 List<Cell> res = new ArrayList<>(); 4114 4115 while (scanner.next(res)) 4116 ; 4117 assertEquals(1L, res.size()); 4118 } finally { 4119 HBaseTestingUtility.closeRegionAndWAL(this.region); 4120 this.region = null; 4121 } 4122 } 4123 4124 // //////////////////////////////////////////////////////////////////////////// 4125 // Bloom filter test 4126 // //////////////////////////////////////////////////////////////////////////// 4127 @Test 4128 public void testBloomFilterSize() throws IOException { 4129 byte[] fam1 = Bytes.toBytes("fam1"); 4130 byte[] qf1 = Bytes.toBytes("col"); 4131 byte[] val1 = Bytes.toBytes("value1"); 4132 // Create Table 4133 HColumnDescriptor hcd = new HColumnDescriptor(fam1).setMaxVersions(Integer.MAX_VALUE) 4134 .setBloomFilterType(BloomType.ROWCOL); 4135 4136 HTableDescriptor htd = new HTableDescriptor(tableName); 4137 htd.addFamily(hcd); 4138 HRegionInfo info = new HRegionInfo(htd.getTableName(), null, null, false); 4139 this.region = TEST_UTIL.createLocalHRegion(info, htd); 4140 try { 4141 int num_unique_rows = 10; 4142 int duplicate_multiplier = 2; 4143 int num_storefiles = 4; 4144 4145 int version = 0; 4146 for (int f = 0; f < num_storefiles; f++) { 4147 for (int i = 0; i < duplicate_multiplier; i++) { 4148 for (int j = 0; j < num_unique_rows; j++) { 4149 Put put = new Put(Bytes.toBytes("row" + j)); 4150 put.setDurability(Durability.SKIP_WAL); 4151 long ts = version++; 4152 put.addColumn(fam1, qf1, ts, val1); 4153 region.put(put); 4154 } 4155 } 4156 region.flush(true); 4157 } 4158 // before compaction 4159 HStore store = region.getStore(fam1); 4160 Collection<HStoreFile> storeFiles = store.getStorefiles(); 4161 for (HStoreFile storefile : storeFiles) { 4162 StoreFileReader reader = storefile.getReader(); 4163 reader.loadFileInfo(); 4164 reader.loadBloomfilter(); 4165 assertEquals(num_unique_rows * duplicate_multiplier, reader.getEntries()); 4166 assertEquals(num_unique_rows, reader.getFilterEntries()); 4167 } 4168 4169 region.compact(true); 4170 4171 // after compaction 4172 storeFiles = store.getStorefiles(); 4173 for (HStoreFile storefile : storeFiles) { 4174 StoreFileReader reader = storefile.getReader(); 4175 reader.loadFileInfo(); 4176 reader.loadBloomfilter(); 4177 assertEquals(num_unique_rows * duplicate_multiplier * num_storefiles, reader.getEntries()); 4178 assertEquals(num_unique_rows, reader.getFilterEntries()); 4179 } 4180 } finally { 4181 HBaseTestingUtility.closeRegionAndWAL(this.region); 4182 this.region = null; 4183 } 4184 } 4185 4186 @Test 4187 public void testAllColumnsWithBloomFilter() throws IOException { 4188 byte[] TABLE = Bytes.toBytes(name.getMethodName()); 4189 byte[] FAMILY = Bytes.toBytes("family"); 4190 4191 // Create table 4192 HColumnDescriptor hcd = new HColumnDescriptor(FAMILY).setMaxVersions(Integer.MAX_VALUE) 4193 .setBloomFilterType(BloomType.ROWCOL); 4194 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(TABLE)); 4195 htd.addFamily(hcd); 4196 HRegionInfo info = new HRegionInfo(htd.getTableName(), null, null, false); 4197 this.region = TEST_UTIL.createLocalHRegion(info, htd); 4198 try { 4199 // For row:0, col:0: insert versions 1 through 5. 4200 byte row[] = Bytes.toBytes("row:" + 0); 4201 byte column[] = Bytes.toBytes("column:" + 0); 4202 Put put = new Put(row); 4203 put.setDurability(Durability.SKIP_WAL); 4204 for (long idx = 1; idx <= 4; idx++) { 4205 put.addColumn(FAMILY, column, idx, Bytes.toBytes("value-version-" + idx)); 4206 } 4207 region.put(put); 4208 4209 // Flush 4210 region.flush(true); 4211 4212 // Get rows 4213 Get get = new Get(row); 4214 get.setMaxVersions(); 4215 Cell[] kvs = region.get(get).rawCells(); 4216 4217 // Check if rows are correct 4218 assertEquals(4, kvs.length); 4219 checkOneCell(kvs[0], FAMILY, 0, 0, 4); 4220 checkOneCell(kvs[1], FAMILY, 0, 0, 3); 4221 checkOneCell(kvs[2], FAMILY, 0, 0, 2); 4222 checkOneCell(kvs[3], FAMILY, 0, 0, 1); 4223 } finally { 4224 HBaseTestingUtility.closeRegionAndWAL(this.region); 4225 this.region = null; 4226 } 4227 } 4228 4229 /** 4230 * Testcase to cover bug-fix for HBASE-2823 Ensures correct delete when 4231 * issuing delete row on columns with bloom filter set to row+col 4232 * (BloomType.ROWCOL) 4233 */ 4234 @Test 4235 public void testDeleteRowWithBloomFilter() throws IOException { 4236 byte[] familyName = Bytes.toBytes("familyName"); 4237 4238 // Create Table 4239 HColumnDescriptor hcd = new HColumnDescriptor(familyName).setMaxVersions(Integer.MAX_VALUE) 4240 .setBloomFilterType(BloomType.ROWCOL); 4241 4242 HTableDescriptor htd = new HTableDescriptor(tableName); 4243 htd.addFamily(hcd); 4244 HRegionInfo info = new HRegionInfo(htd.getTableName(), null, null, false); 4245 this.region = TEST_UTIL.createLocalHRegion(info, htd); 4246 try { 4247 // Insert some data 4248 byte row[] = Bytes.toBytes("row1"); 4249 byte col[] = Bytes.toBytes("col1"); 4250 4251 Put put = new Put(row); 4252 put.addColumn(familyName, col, 1, Bytes.toBytes("SomeRandomValue")); 4253 region.put(put); 4254 region.flush(true); 4255 4256 Delete del = new Delete(row); 4257 region.delete(del); 4258 region.flush(true); 4259 4260 // Get remaining rows (should have none) 4261 Get get = new Get(row); 4262 get.addColumn(familyName, col); 4263 4264 Cell[] keyValues = region.get(get).rawCells(); 4265 assertTrue(keyValues.length == 0); 4266 } finally { 4267 HBaseTestingUtility.closeRegionAndWAL(this.region); 4268 this.region = null; 4269 } 4270 } 4271 4272 @Test 4273 public void testgetHDFSBlocksDistribution() throws Exception { 4274 HBaseTestingUtility htu = new HBaseTestingUtility(); 4275 // Why do we set the block size in this test? If we set it smaller than the kvs, then we'll 4276 // break up the file in to more pieces that can be distributed across the three nodes and we 4277 // won't be able to have the condition this test asserts; that at least one node has 4278 // a copy of all replicas -- if small block size, then blocks are spread evenly across the 4279 // the three nodes. hfilev3 with tags seems to put us over the block size. St.Ack. 4280 // final int DEFAULT_BLOCK_SIZE = 1024; 4281 // htu.getConfiguration().setLong("dfs.blocksize", DEFAULT_BLOCK_SIZE); 4282 htu.getConfiguration().setInt("dfs.replication", 2); 4283 4284 // set up a cluster with 3 nodes 4285 MiniHBaseCluster cluster = null; 4286 String dataNodeHosts[] = new String[] { "host1", "host2", "host3" }; 4287 int regionServersCount = 3; 4288 4289 try { 4290 cluster = htu.startMiniCluster(1, regionServersCount, dataNodeHosts); 4291 byte[][] families = { fam1, fam2 }; 4292 Table ht = htu.createTable(tableName, families); 4293 4294 // Setting up region 4295 byte row[] = Bytes.toBytes("row1"); 4296 byte col[] = Bytes.toBytes("col1"); 4297 4298 Put put = new Put(row); 4299 put.addColumn(fam1, col, 1, Bytes.toBytes("test1")); 4300 put.addColumn(fam2, col, 1, Bytes.toBytes("test2")); 4301 ht.put(put); 4302 4303 HRegion firstRegion = htu.getHBaseCluster().getRegions(tableName).get(0); 4304 firstRegion.flush(true); 4305 HDFSBlocksDistribution blocksDistribution1 = firstRegion.getHDFSBlocksDistribution(); 4306 4307 // Given the default replication factor is 2 and we have 2 HFiles, 4308 // we will have total of 4 replica of blocks on 3 datanodes; thus there 4309 // must be at least one host that have replica for 2 HFiles. That host's 4310 // weight will be equal to the unique block weight. 4311 long uniqueBlocksWeight1 = blocksDistribution1.getUniqueBlocksTotalWeight(); 4312 StringBuilder sb = new StringBuilder(); 4313 for (String host: blocksDistribution1.getTopHosts()) { 4314 if (sb.length() > 0) sb.append(", "); 4315 sb.append(host); 4316 sb.append("="); 4317 sb.append(blocksDistribution1.getWeight(host)); 4318 } 4319 4320 String topHost = blocksDistribution1.getTopHosts().get(0); 4321 long topHostWeight = blocksDistribution1.getWeight(topHost); 4322 String msg = "uniqueBlocksWeight=" + uniqueBlocksWeight1 + ", topHostWeight=" + 4323 topHostWeight + ", topHost=" + topHost + "; " + sb.toString(); 4324 LOG.info(msg); 4325 assertTrue(msg, uniqueBlocksWeight1 == topHostWeight); 4326 4327 // use the static method to compute the value, it should be the same. 4328 // static method is used by load balancer or other components 4329 HDFSBlocksDistribution blocksDistribution2 = HRegion.computeHDFSBlocksDistribution( 4330 htu.getConfiguration(), firstRegion.getTableDescriptor(), firstRegion.getRegionInfo()); 4331 long uniqueBlocksWeight2 = blocksDistribution2.getUniqueBlocksTotalWeight(); 4332 4333 assertTrue(uniqueBlocksWeight1 == uniqueBlocksWeight2); 4334 4335 ht.close(); 4336 } finally { 4337 if (cluster != null) { 4338 htu.shutdownMiniCluster(); 4339 } 4340 } 4341 } 4342 4343 /** 4344 * Testcase to check state of region initialization task set to ABORTED or not 4345 * if any exceptions during initialization 4346 * 4347 * @throws Exception 4348 */ 4349 @Test 4350 public void testStatusSettingToAbortIfAnyExceptionDuringRegionInitilization() throws Exception { 4351 HRegionInfo info; 4352 try { 4353 FileSystem fs = Mockito.mock(FileSystem.class); 4354 Mockito.when(fs.exists((Path) Mockito.anyObject())).thenThrow(new IOException()); 4355 HTableDescriptor htd = new HTableDescriptor(tableName); 4356 htd.addFamily(new HColumnDescriptor("cf")); 4357 info = new HRegionInfo(htd.getTableName(), HConstants.EMPTY_BYTE_ARRAY, 4358 HConstants.EMPTY_BYTE_ARRAY, false); 4359 Path path = new Path(dir + "testStatusSettingToAbortIfAnyExceptionDuringRegionInitilization"); 4360 region = HRegion.newHRegion(path, null, fs, CONF, info, htd, null); 4361 // region initialization throws IOException and set task state to ABORTED. 4362 region.initialize(); 4363 fail("Region initialization should fail due to IOException"); 4364 } catch (IOException io) { 4365 List<MonitoredTask> tasks = TaskMonitor.get().getTasks(); 4366 for (MonitoredTask monitoredTask : tasks) { 4367 if (!(monitoredTask instanceof MonitoredRPCHandler) 4368 && monitoredTask.getDescription().contains(region.toString())) { 4369 assertTrue("Region state should be ABORTED.", 4370 monitoredTask.getState().equals(MonitoredTask.State.ABORTED)); 4371 break; 4372 } 4373 } 4374 } finally { 4375 HBaseTestingUtility.closeRegionAndWAL(region); 4376 } 4377 } 4378 4379 /** 4380 * Verifies that the .regioninfo file is written on region creation and that 4381 * is recreated if missing during region opening. 4382 */ 4383 @Test 4384 public void testRegionInfoFileCreation() throws IOException { 4385 Path rootDir = new Path(dir + "testRegionInfoFileCreation"); 4386 4387 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 4388 htd.addFamily(new HColumnDescriptor("cf")); 4389 4390 HRegionInfo hri = new HRegionInfo(htd.getTableName()); 4391 4392 // Create a region and skip the initialization (like CreateTableHandler) 4393 HRegion region = HBaseTestingUtility.createRegionAndWAL(hri, rootDir, CONF, htd, false); 4394 Path regionDir = region.getRegionFileSystem().getRegionDir(); 4395 FileSystem fs = region.getRegionFileSystem().getFileSystem(); 4396 HBaseTestingUtility.closeRegionAndWAL(region); 4397 4398 Path regionInfoFile = new Path(regionDir, HRegionFileSystem.REGION_INFO_FILE); 4399 4400 // Verify that the .regioninfo file is present 4401 assertTrue(HRegionFileSystem.REGION_INFO_FILE + " should be present in the region dir", 4402 fs.exists(regionInfoFile)); 4403 4404 // Try to open the region 4405 region = HRegion.openHRegion(rootDir, hri, htd, null, CONF); 4406 assertEquals(regionDir, region.getRegionFileSystem().getRegionDir()); 4407 HBaseTestingUtility.closeRegionAndWAL(region); 4408 4409 // Verify that the .regioninfo file is still there 4410 assertTrue(HRegionFileSystem.REGION_INFO_FILE + " should be present in the region dir", 4411 fs.exists(regionInfoFile)); 4412 4413 // Remove the .regioninfo file and verify is recreated on region open 4414 fs.delete(regionInfoFile, true); 4415 assertFalse(HRegionFileSystem.REGION_INFO_FILE + " should be removed from the region dir", 4416 fs.exists(regionInfoFile)); 4417 4418 region = HRegion.openHRegion(rootDir, hri, htd, null, CONF); 4419// region = TEST_UTIL.openHRegion(hri, htd); 4420 assertEquals(regionDir, region.getRegionFileSystem().getRegionDir()); 4421 HBaseTestingUtility.closeRegionAndWAL(region); 4422 4423 // Verify that the .regioninfo file is still there 4424 assertTrue(HRegionFileSystem.REGION_INFO_FILE + " should be present in the region dir", 4425 fs.exists(new Path(regionDir, HRegionFileSystem.REGION_INFO_FILE))); 4426 } 4427 4428 /** 4429 * TestCase for increment 4430 */ 4431 private static class Incrementer implements Runnable { 4432 private HRegion region; 4433 private final static byte[] incRow = Bytes.toBytes("incRow"); 4434 private final static byte[] family = Bytes.toBytes("family"); 4435 private final static byte[] qualifier = Bytes.toBytes("qualifier"); 4436 private final static long ONE = 1L; 4437 private int incCounter; 4438 4439 public Incrementer(HRegion region, int incCounter) { 4440 this.region = region; 4441 this.incCounter = incCounter; 4442 } 4443 4444 @Override 4445 public void run() { 4446 int count = 0; 4447 while (count < incCounter) { 4448 Increment inc = new Increment(incRow); 4449 inc.addColumn(family, qualifier, ONE); 4450 count++; 4451 try { 4452 region.increment(inc); 4453 } catch (IOException e) { 4454 LOG.info("Count=" + count + ", " + e); 4455 break; 4456 } 4457 } 4458 } 4459 } 4460 4461 /** 4462 * Test case to check increment function with memstore flushing 4463 * @throws Exception 4464 */ 4465 @Test 4466 public void testParallelIncrementWithMemStoreFlush() throws Exception { 4467 byte[] family = Incrementer.family; 4468 this.region = initHRegion(tableName, method, CONF, family); 4469 final HRegion region = this.region; 4470 final AtomicBoolean incrementDone = new AtomicBoolean(false); 4471 Runnable flusher = new Runnable() { 4472 @Override 4473 public void run() { 4474 while (!incrementDone.get()) { 4475 try { 4476 region.flush(true); 4477 } catch (Exception e) { 4478 e.printStackTrace(); 4479 } 4480 } 4481 } 4482 }; 4483 4484 // after all increment finished, the row will increment to 20*100 = 2000 4485 int threadNum = 20; 4486 int incCounter = 100; 4487 long expected = (long) threadNum * incCounter; 4488 Thread[] incrementers = new Thread[threadNum]; 4489 Thread flushThread = new Thread(flusher); 4490 for (int i = 0; i < threadNum; i++) { 4491 incrementers[i] = new Thread(new Incrementer(this.region, incCounter)); 4492 incrementers[i].start(); 4493 } 4494 flushThread.start(); 4495 for (int i = 0; i < threadNum; i++) { 4496 incrementers[i].join(); 4497 } 4498 4499 incrementDone.set(true); 4500 flushThread.join(); 4501 4502 Get get = new Get(Incrementer.incRow); 4503 get.addColumn(Incrementer.family, Incrementer.qualifier); 4504 get.setMaxVersions(1); 4505 Result res = this.region.get(get); 4506 List<Cell> kvs = res.getColumnCells(Incrementer.family, Incrementer.qualifier); 4507 4508 // we just got the latest version 4509 assertEquals(1, kvs.size()); 4510 Cell kv = kvs.get(0); 4511 assertEquals(expected, Bytes.toLong(kv.getValueArray(), kv.getValueOffset())); 4512 this.region = null; 4513 } 4514 4515 /** 4516 * TestCase for append 4517 */ 4518 private static class Appender implements Runnable { 4519 private HRegion region; 4520 private final static byte[] appendRow = Bytes.toBytes("appendRow"); 4521 private final static byte[] family = Bytes.toBytes("family"); 4522 private final static byte[] qualifier = Bytes.toBytes("qualifier"); 4523 private final static byte[] CHAR = Bytes.toBytes("a"); 4524 private int appendCounter; 4525 4526 public Appender(HRegion region, int appendCounter) { 4527 this.region = region; 4528 this.appendCounter = appendCounter; 4529 } 4530 4531 @Override 4532 public void run() { 4533 int count = 0; 4534 while (count < appendCounter) { 4535 Append app = new Append(appendRow); 4536 app.addColumn(family, qualifier, CHAR); 4537 count++; 4538 try { 4539 region.append(app); 4540 } catch (IOException e) { 4541 LOG.info("Count=" + count + ", max=" + appendCounter + ", " + e); 4542 break; 4543 } 4544 } 4545 } 4546 } 4547 4548 /** 4549 * Test case to check append function with memstore flushing 4550 * @throws Exception 4551 */ 4552 @Test 4553 public void testParallelAppendWithMemStoreFlush() throws Exception { 4554 byte[] family = Appender.family; 4555 this.region = initHRegion(tableName, method, CONF, family); 4556 final HRegion region = this.region; 4557 final AtomicBoolean appendDone = new AtomicBoolean(false); 4558 Runnable flusher = new Runnable() { 4559 @Override 4560 public void run() { 4561 while (!appendDone.get()) { 4562 try { 4563 region.flush(true); 4564 } catch (Exception e) { 4565 e.printStackTrace(); 4566 } 4567 } 4568 } 4569 }; 4570 4571 // After all append finished, the value will append to threadNum * 4572 // appendCounter Appender.CHAR 4573 int threadNum = 20; 4574 int appendCounter = 100; 4575 byte[] expected = new byte[threadNum * appendCounter]; 4576 for (int i = 0; i < threadNum * appendCounter; i++) { 4577 System.arraycopy(Appender.CHAR, 0, expected, i, 1); 4578 } 4579 Thread[] appenders = new Thread[threadNum]; 4580 Thread flushThread = new Thread(flusher); 4581 for (int i = 0; i < threadNum; i++) { 4582 appenders[i] = new Thread(new Appender(this.region, appendCounter)); 4583 appenders[i].start(); 4584 } 4585 flushThread.start(); 4586 for (int i = 0; i < threadNum; i++) { 4587 appenders[i].join(); 4588 } 4589 4590 appendDone.set(true); 4591 flushThread.join(); 4592 4593 Get get = new Get(Appender.appendRow); 4594 get.addColumn(Appender.family, Appender.qualifier); 4595 get.setMaxVersions(1); 4596 Result res = this.region.get(get); 4597 List<Cell> kvs = res.getColumnCells(Appender.family, Appender.qualifier); 4598 4599 // we just got the latest version 4600 assertEquals(1, kvs.size()); 4601 Cell kv = kvs.get(0); 4602 byte[] appendResult = new byte[kv.getValueLength()]; 4603 System.arraycopy(kv.getValueArray(), kv.getValueOffset(), appendResult, 0, kv.getValueLength()); 4604 assertArrayEquals(expected, appendResult); 4605 this.region = null; 4606 } 4607 4608 /** 4609 * Test case to check put function with memstore flushing for same row, same ts 4610 * @throws Exception 4611 */ 4612 @Test 4613 public void testPutWithMemStoreFlush() throws Exception { 4614 byte[] family = Bytes.toBytes("family"); 4615 byte[] qualifier = Bytes.toBytes("qualifier"); 4616 byte[] row = Bytes.toBytes("putRow"); 4617 byte[] value = null; 4618 this.region = initHRegion(tableName, method, CONF, family); 4619 Put put = null; 4620 Get get = null; 4621 List<Cell> kvs = null; 4622 Result res = null; 4623 4624 put = new Put(row); 4625 value = Bytes.toBytes("value0"); 4626 put.addColumn(family, qualifier, 1234567L, value); 4627 region.put(put); 4628 get = new Get(row); 4629 get.addColumn(family, qualifier); 4630 get.setMaxVersions(); 4631 res = this.region.get(get); 4632 kvs = res.getColumnCells(family, qualifier); 4633 assertEquals(1, kvs.size()); 4634 assertArrayEquals(Bytes.toBytes("value0"), CellUtil.cloneValue(kvs.get(0))); 4635 4636 region.flush(true); 4637 get = new Get(row); 4638 get.addColumn(family, qualifier); 4639 get.setMaxVersions(); 4640 res = this.region.get(get); 4641 kvs = res.getColumnCells(family, qualifier); 4642 assertEquals(1, kvs.size()); 4643 assertArrayEquals(Bytes.toBytes("value0"), CellUtil.cloneValue(kvs.get(0))); 4644 4645 put = new Put(row); 4646 value = Bytes.toBytes("value1"); 4647 put.addColumn(family, qualifier, 1234567L, value); 4648 region.put(put); 4649 get = new Get(row); 4650 get.addColumn(family, qualifier); 4651 get.setMaxVersions(); 4652 res = this.region.get(get); 4653 kvs = res.getColumnCells(family, qualifier); 4654 assertEquals(1, kvs.size()); 4655 assertArrayEquals(Bytes.toBytes("value1"), CellUtil.cloneValue(kvs.get(0))); 4656 4657 region.flush(true); 4658 get = new Get(row); 4659 get.addColumn(family, qualifier); 4660 get.setMaxVersions(); 4661 res = this.region.get(get); 4662 kvs = res.getColumnCells(family, qualifier); 4663 assertEquals(1, kvs.size()); 4664 assertArrayEquals(Bytes.toBytes("value1"), CellUtil.cloneValue(kvs.get(0))); 4665 } 4666 4667 @Test 4668 public void testDurability() throws Exception { 4669 // there are 5 x 5 cases: 4670 // table durability(SYNC,FSYNC,ASYC,SKIP,USE_DEFAULT) x mutation 4671 // durability(SYNC,FSYNC,ASYC,SKIP,USE_DEFAULT) 4672 4673 // expected cases for append and sync wal 4674 durabilityTest(method, Durability.SYNC_WAL, Durability.SYNC_WAL, 0, true, true, false); 4675 durabilityTest(method, Durability.SYNC_WAL, Durability.FSYNC_WAL, 0, true, true, false); 4676 durabilityTest(method, Durability.SYNC_WAL, Durability.USE_DEFAULT, 0, true, true, false); 4677 4678 durabilityTest(method, Durability.FSYNC_WAL, Durability.SYNC_WAL, 0, true, true, false); 4679 durabilityTest(method, Durability.FSYNC_WAL, Durability.FSYNC_WAL, 0, true, true, false); 4680 durabilityTest(method, Durability.FSYNC_WAL, Durability.USE_DEFAULT, 0, true, true, false); 4681 4682 durabilityTest(method, Durability.ASYNC_WAL, Durability.SYNC_WAL, 0, true, true, false); 4683 durabilityTest(method, Durability.ASYNC_WAL, Durability.FSYNC_WAL, 0, true, true, false); 4684 4685 durabilityTest(method, Durability.SKIP_WAL, Durability.SYNC_WAL, 0, true, true, false); 4686 durabilityTest(method, Durability.SKIP_WAL, Durability.FSYNC_WAL, 0, true, true, false); 4687 4688 durabilityTest(method, Durability.USE_DEFAULT, Durability.SYNC_WAL, 0, true, true, false); 4689 durabilityTest(method, Durability.USE_DEFAULT, Durability.FSYNC_WAL, 0, true, true, false); 4690 durabilityTest(method, Durability.USE_DEFAULT, Durability.USE_DEFAULT, 0, true, true, false); 4691 4692 // expected cases for async wal 4693 durabilityTest(method, Durability.SYNC_WAL, Durability.ASYNC_WAL, 0, true, false, false); 4694 durabilityTest(method, Durability.FSYNC_WAL, Durability.ASYNC_WAL, 0, true, false, false); 4695 durabilityTest(method, Durability.ASYNC_WAL, Durability.ASYNC_WAL, 0, true, false, false); 4696 durabilityTest(method, Durability.SKIP_WAL, Durability.ASYNC_WAL, 0, true, false, false); 4697 durabilityTest(method, Durability.USE_DEFAULT, Durability.ASYNC_WAL, 0, true, false, false); 4698 durabilityTest(method, Durability.ASYNC_WAL, Durability.USE_DEFAULT, 0, true, false, false); 4699 4700 durabilityTest(method, Durability.SYNC_WAL, Durability.ASYNC_WAL, 5000, true, false, true); 4701 durabilityTest(method, Durability.FSYNC_WAL, Durability.ASYNC_WAL, 5000, true, false, true); 4702 durabilityTest(method, Durability.ASYNC_WAL, Durability.ASYNC_WAL, 5000, true, false, true); 4703 durabilityTest(method, Durability.SKIP_WAL, Durability.ASYNC_WAL, 5000, true, false, true); 4704 durabilityTest(method, Durability.USE_DEFAULT, Durability.ASYNC_WAL, 5000, true, false, true); 4705 durabilityTest(method, Durability.ASYNC_WAL, Durability.USE_DEFAULT, 5000, true, false, true); 4706 4707 // expect skip wal cases 4708 durabilityTest(method, Durability.SYNC_WAL, Durability.SKIP_WAL, 0, false, false, false); 4709 durabilityTest(method, Durability.FSYNC_WAL, Durability.SKIP_WAL, 0, false, false, false); 4710 durabilityTest(method, Durability.ASYNC_WAL, Durability.SKIP_WAL, 0, false, false, false); 4711 durabilityTest(method, Durability.SKIP_WAL, Durability.SKIP_WAL, 0, false, false, false); 4712 durabilityTest(method, Durability.USE_DEFAULT, Durability.SKIP_WAL, 0, false, false, false); 4713 durabilityTest(method, Durability.SKIP_WAL, Durability.USE_DEFAULT, 0, false, false, false); 4714 4715 } 4716 4717 private void durabilityTest(String method, Durability tableDurability, 4718 Durability mutationDurability, long timeout, boolean expectAppend, final boolean expectSync, 4719 final boolean expectSyncFromLogSyncer) throws Exception { 4720 Configuration conf = HBaseConfiguration.create(CONF); 4721 method = method + "_" + tableDurability.name() + "_" + mutationDurability.name(); 4722 byte[] family = Bytes.toBytes("family"); 4723 Path logDir = new Path(new Path(dir + method), "log"); 4724 final Configuration walConf = new Configuration(conf); 4725 FSUtils.setRootDir(walConf, logDir); 4726 // XXX: The spied AsyncFSWAL can not work properly because of a Mockito defect that can not 4727 // deal with classes which have a field of an inner class. See discussions in HBASE-15536. 4728 walConf.set(WALFactory.WAL_PROVIDER, "filesystem"); 4729 final WALFactory wals = new WALFactory(walConf, UUID.randomUUID().toString()); 4730 final WAL wal = spy(wals.getWAL(RegionInfoBuilder.newBuilder(tableName).build())); 4731 this.region = initHRegion(tableName, HConstants.EMPTY_START_ROW, 4732 HConstants.EMPTY_END_ROW, false, tableDurability, wal, 4733 new byte[][] { family }); 4734 4735 Put put = new Put(Bytes.toBytes("r1")); 4736 put.addColumn(family, Bytes.toBytes("q1"), Bytes.toBytes("v1")); 4737 put.setDurability(mutationDurability); 4738 region.put(put); 4739 4740 //verify append called or not 4741 verify(wal, expectAppend ? times(1) : never()) 4742 .append((HRegionInfo)any(), (WALKeyImpl)any(), 4743 (WALEdit)any(), Mockito.anyBoolean()); 4744 4745 // verify sync called or not 4746 if (expectSync || expectSyncFromLogSyncer) { 4747 TEST_UTIL.waitFor(timeout, new Waiter.Predicate<Exception>() { 4748 @Override 4749 public boolean evaluate() throws Exception { 4750 try { 4751 if (expectSync) { 4752 verify(wal, times(1)).sync(anyLong()); // Hregion calls this one 4753 } else if (expectSyncFromLogSyncer) { 4754 verify(wal, times(1)).sync(); // wal syncer calls this one 4755 } 4756 } catch (Throwable ignore) { 4757 } 4758 return true; 4759 } 4760 }); 4761 } else { 4762 //verify(wal, never()).sync(anyLong()); 4763 verify(wal, never()).sync(); 4764 } 4765 4766 HBaseTestingUtility.closeRegionAndWAL(this.region); 4767 wals.close(); 4768 this.region = null; 4769 } 4770 4771 @Test 4772 public void testRegionReplicaSecondary() throws IOException { 4773 // create a primary region, load some data and flush 4774 // create a secondary region, and do a get against that 4775 Path rootDir = new Path(dir + name.getMethodName()); 4776 FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootDir); 4777 4778 byte[][] families = new byte[][] { 4779 Bytes.toBytes("cf1"), Bytes.toBytes("cf2"), Bytes.toBytes("cf3") 4780 }; 4781 byte[] cq = Bytes.toBytes("cq"); 4782 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 4783 for (byte[] family : families) { 4784 htd.addFamily(new HColumnDescriptor(family)); 4785 } 4786 4787 long time = System.currentTimeMillis(); 4788 HRegionInfo primaryHri = new HRegionInfo(htd.getTableName(), 4789 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4790 false, time, 0); 4791 HRegionInfo secondaryHri = new HRegionInfo(htd.getTableName(), 4792 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4793 false, time, 1); 4794 4795 HRegion primaryRegion = null, secondaryRegion = null; 4796 4797 try { 4798 primaryRegion = HBaseTestingUtility.createRegionAndWAL(primaryHri, 4799 rootDir, TEST_UTIL.getConfiguration(), htd); 4800 4801 // load some data 4802 putData(primaryRegion, 0, 1000, cq, families); 4803 4804 // flush region 4805 primaryRegion.flush(true); 4806 4807 // open secondary region 4808 secondaryRegion = HRegion.openHRegion(rootDir, secondaryHri, htd, null, CONF); 4809 4810 verifyData(secondaryRegion, 0, 1000, cq, families); 4811 } finally { 4812 if (primaryRegion != null) { 4813 HBaseTestingUtility.closeRegionAndWAL(primaryRegion); 4814 } 4815 if (secondaryRegion != null) { 4816 HBaseTestingUtility.closeRegionAndWAL(secondaryRegion); 4817 } 4818 } 4819 } 4820 4821 @Test 4822 public void testRegionReplicaSecondaryIsReadOnly() throws IOException { 4823 // create a primary region, load some data and flush 4824 // create a secondary region, and do a put against that 4825 Path rootDir = new Path(dir + name.getMethodName()); 4826 FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootDir); 4827 4828 byte[][] families = new byte[][] { 4829 Bytes.toBytes("cf1"), Bytes.toBytes("cf2"), Bytes.toBytes("cf3") 4830 }; 4831 byte[] cq = Bytes.toBytes("cq"); 4832 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 4833 for (byte[] family : families) { 4834 htd.addFamily(new HColumnDescriptor(family)); 4835 } 4836 4837 long time = System.currentTimeMillis(); 4838 HRegionInfo primaryHri = new HRegionInfo(htd.getTableName(), 4839 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4840 false, time, 0); 4841 HRegionInfo secondaryHri = new HRegionInfo(htd.getTableName(), 4842 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4843 false, time, 1); 4844 4845 HRegion primaryRegion = null, secondaryRegion = null; 4846 4847 try { 4848 primaryRegion = HBaseTestingUtility.createRegionAndWAL(primaryHri, 4849 rootDir, TEST_UTIL.getConfiguration(), htd); 4850 4851 // load some data 4852 putData(primaryRegion, 0, 1000, cq, families); 4853 4854 // flush region 4855 primaryRegion.flush(true); 4856 4857 // open secondary region 4858 secondaryRegion = HRegion.openHRegion(rootDir, secondaryHri, htd, null, CONF); 4859 4860 try { 4861 putData(secondaryRegion, 0, 1000, cq, families); 4862 fail("Should have thrown exception"); 4863 } catch (IOException ex) { 4864 // expected 4865 } 4866 } finally { 4867 if (primaryRegion != null) { 4868 HBaseTestingUtility.closeRegionAndWAL(primaryRegion); 4869 } 4870 if (secondaryRegion != null) { 4871 HBaseTestingUtility.closeRegionAndWAL(secondaryRegion); 4872 } 4873 } 4874 } 4875 4876 static WALFactory createWALFactory(Configuration conf, Path rootDir) throws IOException { 4877 Configuration confForWAL = new Configuration(conf); 4878 confForWAL.set(HConstants.HBASE_DIR, rootDir.toString()); 4879 return new WALFactory(confForWAL, "hregion-" + RandomStringUtils.randomNumeric(8)); 4880 } 4881 4882 @Test 4883 public void testCompactionFromPrimary() throws IOException { 4884 Path rootDir = new Path(dir + name.getMethodName()); 4885 FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootDir); 4886 4887 byte[][] families = new byte[][] { 4888 Bytes.toBytes("cf1"), Bytes.toBytes("cf2"), Bytes.toBytes("cf3") 4889 }; 4890 byte[] cq = Bytes.toBytes("cq"); 4891 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 4892 for (byte[] family : families) { 4893 htd.addFamily(new HColumnDescriptor(family)); 4894 } 4895 4896 long time = System.currentTimeMillis(); 4897 HRegionInfo primaryHri = new HRegionInfo(htd.getTableName(), 4898 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4899 false, time, 0); 4900 HRegionInfo secondaryHri = new HRegionInfo(htd.getTableName(), 4901 HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW, 4902 false, time, 1); 4903 4904 HRegion primaryRegion = null, secondaryRegion = null; 4905 4906 try { 4907 primaryRegion = HBaseTestingUtility.createRegionAndWAL(primaryHri, 4908 rootDir, TEST_UTIL.getConfiguration(), htd); 4909 4910 // load some data 4911 putData(primaryRegion, 0, 1000, cq, families); 4912 4913 // flush region 4914 primaryRegion.flush(true); 4915 4916 // open secondary region 4917 secondaryRegion = HRegion.openHRegion(rootDir, secondaryHri, htd, null, CONF); 4918 4919 // move the file of the primary region to the archive, simulating a compaction 4920 Collection<HStoreFile> storeFiles = primaryRegion.getStore(families[0]).getStorefiles(); 4921 primaryRegion.getRegionFileSystem().removeStoreFiles(Bytes.toString(families[0]), storeFiles); 4922 Collection<StoreFileInfo> storeFileInfos = primaryRegion.getRegionFileSystem() 4923 .getStoreFiles(families[0]); 4924 Assert.assertTrue(storeFileInfos == null || storeFileInfos.isEmpty()); 4925 4926 verifyData(secondaryRegion, 0, 1000, cq, families); 4927 } finally { 4928 if (primaryRegion != null) { 4929 HBaseTestingUtility.closeRegionAndWAL(primaryRegion); 4930 } 4931 if (secondaryRegion != null) { 4932 HBaseTestingUtility.closeRegionAndWAL(secondaryRegion); 4933 } 4934 } 4935 } 4936 4937 private void putData(int startRow, int numRows, byte[] qf, byte[]... families) throws 4938 IOException { 4939 putData(this.region, startRow, numRows, qf, families); 4940 } 4941 4942 private void putData(HRegion region, 4943 int startRow, int numRows, byte[] qf, byte[]... families) throws IOException { 4944 putData(region, Durability.SKIP_WAL, startRow, numRows, qf, families); 4945 } 4946 4947 static void putData(HRegion region, Durability durability, 4948 int startRow, int numRows, byte[] qf, byte[]... families) throws IOException { 4949 for (int i = startRow; i < startRow + numRows; i++) { 4950 Put put = new Put(Bytes.toBytes("" + i)); 4951 put.setDurability(durability); 4952 for (byte[] family : families) { 4953 put.addColumn(family, qf, null); 4954 } 4955 region.put(put); 4956 LOG.info(put.toString()); 4957 } 4958 } 4959 4960 static void verifyData(HRegion newReg, int startRow, int numRows, byte[] qf, byte[]... families) 4961 throws IOException { 4962 for (int i = startRow; i < startRow + numRows; i++) { 4963 byte[] row = Bytes.toBytes("" + i); 4964 Get get = new Get(row); 4965 for (byte[] family : families) { 4966 get.addColumn(family, qf); 4967 } 4968 Result result = newReg.get(get); 4969 Cell[] raw = result.rawCells(); 4970 assertEquals(families.length, result.size()); 4971 for (int j = 0; j < families.length; j++) { 4972 assertTrue(CellUtil.matchingRows(raw[j], row)); 4973 assertTrue(CellUtil.matchingFamily(raw[j], families[j])); 4974 assertTrue(CellUtil.matchingQualifier(raw[j], qf)); 4975 } 4976 } 4977 } 4978 4979 static void assertGet(final HRegion r, final byte[] family, final byte[] k) throws IOException { 4980 // Now I have k, get values out and assert they are as expected. 4981 Get get = new Get(k).addFamily(family).setMaxVersions(); 4982 Cell[] results = r.get(get).rawCells(); 4983 for (int j = 0; j < results.length; j++) { 4984 byte[] tmp = CellUtil.cloneValue(results[j]); 4985 // Row should be equal to value every time. 4986 assertTrue(Bytes.equals(k, tmp)); 4987 } 4988 } 4989 4990 /* 4991 * Assert first value in the passed region is <code>firstValue</code>. 4992 * 4993 * @param r 4994 * 4995 * @param fs 4996 * 4997 * @param firstValue 4998 * 4999 * @throws IOException 5000 */ 5001 protected void assertScan(final HRegion r, final byte[] fs, final byte[] firstValue) 5002 throws IOException { 5003 byte[][] families = { fs }; 5004 Scan scan = new Scan(); 5005 for (int i = 0; i < families.length; i++) 5006 scan.addFamily(families[i]); 5007 InternalScanner s = r.getScanner(scan); 5008 try { 5009 List<Cell> curVals = new ArrayList<>(); 5010 boolean first = true; 5011 OUTER_LOOP: while (s.next(curVals)) { 5012 for (Cell kv : curVals) { 5013 byte[] val = CellUtil.cloneValue(kv); 5014 byte[] curval = val; 5015 if (first) { 5016 first = false; 5017 assertTrue(Bytes.compareTo(curval, firstValue) == 0); 5018 } else { 5019 // Not asserting anything. Might as well break. 5020 break OUTER_LOOP; 5021 } 5022 } 5023 } 5024 } finally { 5025 s.close(); 5026 } 5027 } 5028 5029 /** 5030 * Test that we get the expected flush results back 5031 */ 5032 @Test 5033 public void testFlushResult() throws IOException { 5034 byte[] family = Bytes.toBytes("family"); 5035 5036 this.region = initHRegion(tableName, method, family); 5037 5038 // empty memstore, flush doesn't run 5039 HRegion.FlushResult fr = region.flush(true); 5040 assertFalse(fr.isFlushSucceeded()); 5041 assertFalse(fr.isCompactionNeeded()); 5042 5043 // Flush enough files to get up to the threshold, doesn't need compactions 5044 for (int i = 0; i < 2; i++) { 5045 Put put = new Put(tableName.toBytes()).addColumn(family, family, tableName.toBytes()); 5046 region.put(put); 5047 fr = region.flush(true); 5048 assertTrue(fr.isFlushSucceeded()); 5049 assertFalse(fr.isCompactionNeeded()); 5050 } 5051 5052 // Two flushes after the threshold, compactions are needed 5053 for (int i = 0; i < 2; i++) { 5054 Put put = new Put(tableName.toBytes()).addColumn(family, family, tableName.toBytes()); 5055 region.put(put); 5056 fr = region.flush(true); 5057 assertTrue(fr.isFlushSucceeded()); 5058 assertTrue(fr.isCompactionNeeded()); 5059 } 5060 } 5061 5062 protected Configuration initSplit() { 5063 // Always compact if there is more than one store file. 5064 CONF.setInt("hbase.hstore.compactionThreshold", 2); 5065 5066 CONF.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, 10 * 1000); 5067 5068 // Increase the amount of time between client retries 5069 CONF.setLong("hbase.client.pause", 15 * 1000); 5070 5071 // This size should make it so we always split using the addContent 5072 // below. After adding all data, the first region is 1.3M 5073 CONF.setLong(HConstants.HREGION_MAX_FILESIZE, 1024 * 128); 5074 return CONF; 5075 } 5076 5077 /** 5078 * @return A region on which you must call 5079 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when done. 5080 */ 5081 protected HRegion initHRegion(TableName tableName, String callingMethod, Configuration conf, 5082 byte[]... families) throws IOException { 5083 return initHRegion(tableName, callingMethod, conf, false, families); 5084 } 5085 5086 /** 5087 * @return A region on which you must call 5088 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when done. 5089 */ 5090 protected HRegion initHRegion(TableName tableName, String callingMethod, Configuration conf, 5091 boolean isReadOnly, byte[]... families) throws IOException { 5092 return initHRegion(tableName, null, null, callingMethod, conf, isReadOnly, families); 5093 } 5094 5095 protected HRegion initHRegion(TableName tableName, byte[] startKey, byte[] stopKey, 5096 String callingMethod, Configuration conf, boolean isReadOnly, byte[]... families) 5097 throws IOException { 5098 Path logDir = TEST_UTIL.getDataTestDirOnTestFS(callingMethod + ".log"); 5099 ChunkCreator.initialize(MemStoreLABImpl.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null); 5100 HRegionInfo hri = new HRegionInfo(tableName, startKey, stopKey); 5101 final WAL wal = HBaseTestingUtility.createWal(conf, logDir, hri); 5102 return initHRegion(tableName, startKey, stopKey, isReadOnly, 5103 Durability.SYNC_WAL, wal, families); 5104 } 5105 5106 /** 5107 * @return A region on which you must call 5108 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} when done. 5109 */ 5110 public HRegion initHRegion(TableName tableName, byte[] startKey, byte[] stopKey, 5111 boolean isReadOnly, Durability durability, WAL wal, byte[]... families) throws IOException { 5112 return TEST_UTIL.createLocalHRegion(tableName, startKey, stopKey, 5113 isReadOnly, durability, wal, families); 5114 } 5115 5116 /** 5117 * Assert that the passed in Cell has expected contents for the specified row, 5118 * column & timestamp. 5119 */ 5120 private void checkOneCell(Cell kv, byte[] cf, int rowIdx, int colIdx, long ts) { 5121 String ctx = "rowIdx=" + rowIdx + "; colIdx=" + colIdx + "; ts=" + ts; 5122 assertEquals("Row mismatch which checking: " + ctx, "row:" + rowIdx, 5123 Bytes.toString(CellUtil.cloneRow(kv))); 5124 assertEquals("ColumnFamily mismatch while checking: " + ctx, Bytes.toString(cf), 5125 Bytes.toString(CellUtil.cloneFamily(kv))); 5126 assertEquals("Column qualifier mismatch while checking: " + ctx, "column:" + colIdx, 5127 Bytes.toString(CellUtil.cloneQualifier(kv))); 5128 assertEquals("Timestamp mismatch while checking: " + ctx, ts, kv.getTimestamp()); 5129 assertEquals("Value mismatch while checking: " + ctx, "value-version-" + ts, 5130 Bytes.toString(CellUtil.cloneValue(kv))); 5131 } 5132 5133 @Test 5134 public void testReverseScanner_FromMemStore_SingleCF_Normal() 5135 throws IOException { 5136 byte[] rowC = Bytes.toBytes("rowC"); 5137 byte[] rowA = Bytes.toBytes("rowA"); 5138 byte[] rowB = Bytes.toBytes("rowB"); 5139 byte[] cf = Bytes.toBytes("CF"); 5140 byte[][] families = { cf }; 5141 byte[] col = Bytes.toBytes("C"); 5142 long ts = 1; 5143 this.region = initHRegion(tableName, method, families); 5144 try { 5145 KeyValue kv1 = new KeyValue(rowC, cf, col, ts, KeyValue.Type.Put, null); 5146 KeyValue kv11 = new KeyValue(rowC, cf, col, ts + 1, KeyValue.Type.Put, 5147 null); 5148 KeyValue kv2 = new KeyValue(rowA, cf, col, ts, KeyValue.Type.Put, null); 5149 KeyValue kv3 = new KeyValue(rowB, cf, col, ts, KeyValue.Type.Put, null); 5150 Put put = null; 5151 put = new Put(rowC); 5152 put.add(kv1); 5153 put.add(kv11); 5154 region.put(put); 5155 put = new Put(rowA); 5156 put.add(kv2); 5157 region.put(put); 5158 put = new Put(rowB); 5159 put.add(kv3); 5160 region.put(put); 5161 5162 Scan scan = new Scan(rowC); 5163 scan.setMaxVersions(5); 5164 scan.setReversed(true); 5165 InternalScanner scanner = region.getScanner(scan); 5166 List<Cell> currRow = new ArrayList<>(); 5167 boolean hasNext = scanner.next(currRow); 5168 assertEquals(2, currRow.size()); 5169 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5170 .get(0).getRowLength(), rowC, 0, rowC.length)); 5171 assertTrue(hasNext); 5172 currRow.clear(); 5173 hasNext = scanner.next(currRow); 5174 assertEquals(1, currRow.size()); 5175 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5176 .get(0).getRowLength(), rowB, 0, rowB.length)); 5177 assertTrue(hasNext); 5178 currRow.clear(); 5179 hasNext = scanner.next(currRow); 5180 assertEquals(1, currRow.size()); 5181 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5182 .get(0).getRowLength(), rowA, 0, rowA.length)); 5183 assertFalse(hasNext); 5184 scanner.close(); 5185 } finally { 5186 HBaseTestingUtility.closeRegionAndWAL(this.region); 5187 this.region = null; 5188 } 5189 } 5190 5191 @Test 5192 public void testReverseScanner_FromMemStore_SingleCF_LargerKey() 5193 throws IOException { 5194 byte[] rowC = Bytes.toBytes("rowC"); 5195 byte[] rowA = Bytes.toBytes("rowA"); 5196 byte[] rowB = Bytes.toBytes("rowB"); 5197 byte[] rowD = Bytes.toBytes("rowD"); 5198 byte[] cf = Bytes.toBytes("CF"); 5199 byte[][] families = { cf }; 5200 byte[] col = Bytes.toBytes("C"); 5201 long ts = 1; 5202 this.region = initHRegion(tableName, method, families); 5203 try { 5204 KeyValue kv1 = new KeyValue(rowC, cf, col, ts, KeyValue.Type.Put, null); 5205 KeyValue kv11 = new KeyValue(rowC, cf, col, ts + 1, KeyValue.Type.Put, 5206 null); 5207 KeyValue kv2 = new KeyValue(rowA, cf, col, ts, KeyValue.Type.Put, null); 5208 KeyValue kv3 = new KeyValue(rowB, cf, col, ts, KeyValue.Type.Put, null); 5209 Put put = null; 5210 put = new Put(rowC); 5211 put.add(kv1); 5212 put.add(kv11); 5213 region.put(put); 5214 put = new Put(rowA); 5215 put.add(kv2); 5216 region.put(put); 5217 put = new Put(rowB); 5218 put.add(kv3); 5219 region.put(put); 5220 5221 Scan scan = new Scan(rowD); 5222 List<Cell> currRow = new ArrayList<>(); 5223 scan.setReversed(true); 5224 scan.setMaxVersions(5); 5225 InternalScanner scanner = region.getScanner(scan); 5226 boolean hasNext = scanner.next(currRow); 5227 assertEquals(2, currRow.size()); 5228 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5229 .get(0).getRowLength(), rowC, 0, rowC.length)); 5230 assertTrue(hasNext); 5231 currRow.clear(); 5232 hasNext = scanner.next(currRow); 5233 assertEquals(1, currRow.size()); 5234 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5235 .get(0).getRowLength(), rowB, 0, rowB.length)); 5236 assertTrue(hasNext); 5237 currRow.clear(); 5238 hasNext = scanner.next(currRow); 5239 assertEquals(1, currRow.size()); 5240 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5241 .get(0).getRowLength(), rowA, 0, rowA.length)); 5242 assertFalse(hasNext); 5243 scanner.close(); 5244 } finally { 5245 HBaseTestingUtility.closeRegionAndWAL(this.region); 5246 this.region = null; 5247 } 5248 } 5249 5250 @Test 5251 public void testReverseScanner_FromMemStore_SingleCF_FullScan() 5252 throws IOException { 5253 byte[] rowC = Bytes.toBytes("rowC"); 5254 byte[] rowA = Bytes.toBytes("rowA"); 5255 byte[] rowB = Bytes.toBytes("rowB"); 5256 byte[] cf = Bytes.toBytes("CF"); 5257 byte[][] families = { cf }; 5258 byte[] col = Bytes.toBytes("C"); 5259 long ts = 1; 5260 this.region = initHRegion(tableName, method, families); 5261 try { 5262 KeyValue kv1 = new KeyValue(rowC, cf, col, ts, KeyValue.Type.Put, null); 5263 KeyValue kv11 = new KeyValue(rowC, cf, col, ts + 1, KeyValue.Type.Put, 5264 null); 5265 KeyValue kv2 = new KeyValue(rowA, cf, col, ts, KeyValue.Type.Put, null); 5266 KeyValue kv3 = new KeyValue(rowB, cf, col, ts, KeyValue.Type.Put, null); 5267 Put put = null; 5268 put = new Put(rowC); 5269 put.add(kv1); 5270 put.add(kv11); 5271 region.put(put); 5272 put = new Put(rowA); 5273 put.add(kv2); 5274 region.put(put); 5275 put = new Put(rowB); 5276 put.add(kv3); 5277 region.put(put); 5278 Scan scan = new Scan(); 5279 List<Cell> currRow = new ArrayList<>(); 5280 scan.setReversed(true); 5281 InternalScanner scanner = region.getScanner(scan); 5282 boolean hasNext = scanner.next(currRow); 5283 assertEquals(1, currRow.size()); 5284 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5285 .get(0).getRowLength(), rowC, 0, rowC.length)); 5286 assertTrue(hasNext); 5287 currRow.clear(); 5288 hasNext = scanner.next(currRow); 5289 assertEquals(1, currRow.size()); 5290 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5291 .get(0).getRowLength(), rowB, 0, rowB.length)); 5292 assertTrue(hasNext); 5293 currRow.clear(); 5294 hasNext = scanner.next(currRow); 5295 assertEquals(1, currRow.size()); 5296 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5297 .get(0).getRowLength(), rowA, 0, rowA.length)); 5298 assertFalse(hasNext); 5299 scanner.close(); 5300 } finally { 5301 HBaseTestingUtility.closeRegionAndWAL(this.region); 5302 this.region = null; 5303 } 5304 } 5305 5306 @Test 5307 public void testReverseScanner_moreRowsMayExistAfter() throws IOException { 5308 // case for "INCLUDE_AND_SEEK_NEXT_ROW & SEEK_NEXT_ROW" endless loop 5309 byte[] rowA = Bytes.toBytes("rowA"); 5310 byte[] rowB = Bytes.toBytes("rowB"); 5311 byte[] rowC = Bytes.toBytes("rowC"); 5312 byte[] rowD = Bytes.toBytes("rowD"); 5313 byte[] rowE = Bytes.toBytes("rowE"); 5314 byte[] cf = Bytes.toBytes("CF"); 5315 byte[][] families = { cf }; 5316 byte[] col1 = Bytes.toBytes("col1"); 5317 byte[] col2 = Bytes.toBytes("col2"); 5318 long ts = 1; 5319 this.region = initHRegion(tableName, method, families); 5320 try { 5321 KeyValue kv1 = new KeyValue(rowA, cf, col1, ts, KeyValue.Type.Put, null); 5322 KeyValue kv2 = new KeyValue(rowB, cf, col1, ts, KeyValue.Type.Put, null); 5323 KeyValue kv3 = new KeyValue(rowC, cf, col1, ts, KeyValue.Type.Put, null); 5324 KeyValue kv4_1 = new KeyValue(rowD, cf, col1, ts, KeyValue.Type.Put, null); 5325 KeyValue kv4_2 = new KeyValue(rowD, cf, col2, ts, KeyValue.Type.Put, null); 5326 KeyValue kv5 = new KeyValue(rowE, cf, col1, ts, KeyValue.Type.Put, null); 5327 Put put = null; 5328 put = new Put(rowA); 5329 put.add(kv1); 5330 region.put(put); 5331 put = new Put(rowB); 5332 put.add(kv2); 5333 region.put(put); 5334 put = new Put(rowC); 5335 put.add(kv3); 5336 region.put(put); 5337 put = new Put(rowD); 5338 put.add(kv4_1); 5339 region.put(put); 5340 put = new Put(rowD); 5341 put.add(kv4_2); 5342 region.put(put); 5343 put = new Put(rowE); 5344 put.add(kv5); 5345 region.put(put); 5346 region.flush(true); 5347 Scan scan = new Scan(rowD, rowA); 5348 scan.addColumn(families[0], col1); 5349 scan.setReversed(true); 5350 List<Cell> currRow = new ArrayList<>(); 5351 InternalScanner scanner = region.getScanner(scan); 5352 boolean hasNext = scanner.next(currRow); 5353 assertEquals(1, currRow.size()); 5354 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5355 .get(0).getRowLength(), rowD, 0, rowD.length)); 5356 assertTrue(hasNext); 5357 currRow.clear(); 5358 hasNext = scanner.next(currRow); 5359 assertEquals(1, currRow.size()); 5360 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5361 .get(0).getRowLength(), rowC, 0, rowC.length)); 5362 assertTrue(hasNext); 5363 currRow.clear(); 5364 hasNext = scanner.next(currRow); 5365 assertEquals(1, currRow.size()); 5366 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5367 .get(0).getRowLength(), rowB, 0, rowB.length)); 5368 assertFalse(hasNext); 5369 scanner.close(); 5370 5371 scan = new Scan(rowD, rowA); 5372 scan.addColumn(families[0], col2); 5373 scan.setReversed(true); 5374 currRow.clear(); 5375 scanner = region.getScanner(scan); 5376 hasNext = scanner.next(currRow); 5377 assertEquals(1, currRow.size()); 5378 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5379 .get(0).getRowLength(), rowD, 0, rowD.length)); 5380 scanner.close(); 5381 } finally { 5382 HBaseTestingUtility.closeRegionAndWAL(this.region); 5383 this.region = null; 5384 } 5385 } 5386 5387 @Test 5388 public void testReverseScanner_smaller_blocksize() throws IOException { 5389 // case to ensure no conflict with HFile index optimization 5390 byte[] rowA = Bytes.toBytes("rowA"); 5391 byte[] rowB = Bytes.toBytes("rowB"); 5392 byte[] rowC = Bytes.toBytes("rowC"); 5393 byte[] rowD = Bytes.toBytes("rowD"); 5394 byte[] rowE = Bytes.toBytes("rowE"); 5395 byte[] cf = Bytes.toBytes("CF"); 5396 byte[][] families = { cf }; 5397 byte[] col1 = Bytes.toBytes("col1"); 5398 byte[] col2 = Bytes.toBytes("col2"); 5399 long ts = 1; 5400 HBaseConfiguration config = new HBaseConfiguration(); 5401 config.setInt("test.block.size", 1); 5402 this.region = initHRegion(tableName, method, config, families); 5403 try { 5404 KeyValue kv1 = new KeyValue(rowA, cf, col1, ts, KeyValue.Type.Put, null); 5405 KeyValue kv2 = new KeyValue(rowB, cf, col1, ts, KeyValue.Type.Put, null); 5406 KeyValue kv3 = new KeyValue(rowC, cf, col1, ts, KeyValue.Type.Put, null); 5407 KeyValue kv4_1 = new KeyValue(rowD, cf, col1, ts, KeyValue.Type.Put, null); 5408 KeyValue kv4_2 = new KeyValue(rowD, cf, col2, ts, KeyValue.Type.Put, null); 5409 KeyValue kv5 = new KeyValue(rowE, cf, col1, ts, KeyValue.Type.Put, null); 5410 Put put = null; 5411 put = new Put(rowA); 5412 put.add(kv1); 5413 region.put(put); 5414 put = new Put(rowB); 5415 put.add(kv2); 5416 region.put(put); 5417 put = new Put(rowC); 5418 put.add(kv3); 5419 region.put(put); 5420 put = new Put(rowD); 5421 put.add(kv4_1); 5422 region.put(put); 5423 put = new Put(rowD); 5424 put.add(kv4_2); 5425 region.put(put); 5426 put = new Put(rowE); 5427 put.add(kv5); 5428 region.put(put); 5429 region.flush(true); 5430 Scan scan = new Scan(rowD, rowA); 5431 scan.addColumn(families[0], col1); 5432 scan.setReversed(true); 5433 List<Cell> currRow = new ArrayList<>(); 5434 InternalScanner scanner = region.getScanner(scan); 5435 boolean hasNext = scanner.next(currRow); 5436 assertEquals(1, currRow.size()); 5437 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5438 .get(0).getRowLength(), rowD, 0, rowD.length)); 5439 assertTrue(hasNext); 5440 currRow.clear(); 5441 hasNext = scanner.next(currRow); 5442 assertEquals(1, currRow.size()); 5443 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5444 .get(0).getRowLength(), rowC, 0, rowC.length)); 5445 assertTrue(hasNext); 5446 currRow.clear(); 5447 hasNext = scanner.next(currRow); 5448 assertEquals(1, currRow.size()); 5449 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5450 .get(0).getRowLength(), rowB, 0, rowB.length)); 5451 assertFalse(hasNext); 5452 scanner.close(); 5453 5454 scan = new Scan(rowD, rowA); 5455 scan.addColumn(families[0], col2); 5456 scan.setReversed(true); 5457 currRow.clear(); 5458 scanner = region.getScanner(scan); 5459 hasNext = scanner.next(currRow); 5460 assertEquals(1, currRow.size()); 5461 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5462 .get(0).getRowLength(), rowD, 0, rowD.length)); 5463 scanner.close(); 5464 } finally { 5465 HBaseTestingUtility.closeRegionAndWAL(this.region); 5466 this.region = null; 5467 } 5468 } 5469 5470 @Test 5471 public void testReverseScanner_FromMemStoreAndHFiles_MultiCFs1() 5472 throws IOException { 5473 byte[] row0 = Bytes.toBytes("row0"); // 1 kv 5474 byte[] row1 = Bytes.toBytes("row1"); // 2 kv 5475 byte[] row2 = Bytes.toBytes("row2"); // 4 kv 5476 byte[] row3 = Bytes.toBytes("row3"); // 2 kv 5477 byte[] row4 = Bytes.toBytes("row4"); // 5 kv 5478 byte[] row5 = Bytes.toBytes("row5"); // 2 kv 5479 byte[] cf1 = Bytes.toBytes("CF1"); 5480 byte[] cf2 = Bytes.toBytes("CF2"); 5481 byte[] cf3 = Bytes.toBytes("CF3"); 5482 byte[][] families = { cf1, cf2, cf3 }; 5483 byte[] col = Bytes.toBytes("C"); 5484 long ts = 1; 5485 HBaseConfiguration conf = new HBaseConfiguration(); 5486 // disable compactions in this test. 5487 conf.setInt("hbase.hstore.compactionThreshold", 10000); 5488 this.region = initHRegion(tableName, method, conf, families); 5489 try { 5490 // kv naming style: kv(row number) totalKvCountInThisRow seq no 5491 KeyValue kv0_1_1 = new KeyValue(row0, cf1, col, ts, KeyValue.Type.Put, 5492 null); 5493 KeyValue kv1_2_1 = new KeyValue(row1, cf2, col, ts, KeyValue.Type.Put, 5494 null); 5495 KeyValue kv1_2_2 = new KeyValue(row1, cf1, col, ts + 1, 5496 KeyValue.Type.Put, null); 5497 KeyValue kv2_4_1 = new KeyValue(row2, cf2, col, ts, KeyValue.Type.Put, 5498 null); 5499 KeyValue kv2_4_2 = new KeyValue(row2, cf1, col, ts, KeyValue.Type.Put, 5500 null); 5501 KeyValue kv2_4_3 = new KeyValue(row2, cf3, col, ts, KeyValue.Type.Put, 5502 null); 5503 KeyValue kv2_4_4 = new KeyValue(row2, cf1, col, ts + 4, 5504 KeyValue.Type.Put, null); 5505 KeyValue kv3_2_1 = new KeyValue(row3, cf2, col, ts, KeyValue.Type.Put, 5506 null); 5507 KeyValue kv3_2_2 = new KeyValue(row3, cf1, col, ts + 4, 5508 KeyValue.Type.Put, null); 5509 KeyValue kv4_5_1 = new KeyValue(row4, cf1, col, ts, KeyValue.Type.Put, 5510 null); 5511 KeyValue kv4_5_2 = new KeyValue(row4, cf3, col, ts, KeyValue.Type.Put, 5512 null); 5513 KeyValue kv4_5_3 = new KeyValue(row4, cf3, col, ts + 5, 5514 KeyValue.Type.Put, null); 5515 KeyValue kv4_5_4 = new KeyValue(row4, cf2, col, ts, KeyValue.Type.Put, 5516 null); 5517 KeyValue kv4_5_5 = new KeyValue(row4, cf1, col, ts + 3, 5518 KeyValue.Type.Put, null); 5519 KeyValue kv5_2_1 = new KeyValue(row5, cf2, col, ts, KeyValue.Type.Put, 5520 null); 5521 KeyValue kv5_2_2 = new KeyValue(row5, cf3, col, ts, KeyValue.Type.Put, 5522 null); 5523 // hfiles(cf1/cf2) :"row1"(1 kv) / "row2"(1 kv) / "row4"(2 kv) 5524 Put put = null; 5525 put = new Put(row1); 5526 put.add(kv1_2_1); 5527 region.put(put); 5528 put = new Put(row2); 5529 put.add(kv2_4_1); 5530 region.put(put); 5531 put = new Put(row4); 5532 put.add(kv4_5_4); 5533 put.add(kv4_5_5); 5534 region.put(put); 5535 region.flush(true); 5536 // hfiles(cf1/cf3) : "row1" (1 kvs) / "row2" (1 kv) / "row4" (2 kv) 5537 put = new Put(row4); 5538 put.add(kv4_5_1); 5539 put.add(kv4_5_3); 5540 region.put(put); 5541 put = new Put(row1); 5542 put.add(kv1_2_2); 5543 region.put(put); 5544 put = new Put(row2); 5545 put.add(kv2_4_4); 5546 region.put(put); 5547 region.flush(true); 5548 // hfiles(cf1/cf3) : "row2"(2 kv) / "row3"(1 kvs) / "row4" (1 kv) 5549 put = new Put(row4); 5550 put.add(kv4_5_2); 5551 region.put(put); 5552 put = new Put(row2); 5553 put.add(kv2_4_2); 5554 put.add(kv2_4_3); 5555 region.put(put); 5556 put = new Put(row3); 5557 put.add(kv3_2_2); 5558 region.put(put); 5559 region.flush(true); 5560 // memstore(cf1/cf2/cf3) : "row0" (1 kvs) / "row3" ( 1 kv) / "row5" (max) 5561 // ( 2 kv) 5562 put = new Put(row0); 5563 put.add(kv0_1_1); 5564 region.put(put); 5565 put = new Put(row3); 5566 put.add(kv3_2_1); 5567 region.put(put); 5568 put = new Put(row5); 5569 put.add(kv5_2_1); 5570 put.add(kv5_2_2); 5571 region.put(put); 5572 // scan range = ["row4", min), skip the max "row5" 5573 Scan scan = new Scan(row4); 5574 scan.setMaxVersions(5); 5575 scan.setBatch(3); 5576 scan.setReversed(true); 5577 InternalScanner scanner = region.getScanner(scan); 5578 List<Cell> currRow = new ArrayList<>(); 5579 boolean hasNext = false; 5580 // 1. scan out "row4" (5 kvs), "row5" can't be scanned out since not 5581 // included in scan range 5582 // "row4" takes 2 next() calls since batch=3 5583 hasNext = scanner.next(currRow); 5584 assertEquals(3, currRow.size()); 5585 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5586 .get(0).getRowLength(), row4, 0, row4.length)); 5587 assertTrue(hasNext); 5588 currRow.clear(); 5589 hasNext = scanner.next(currRow); 5590 assertEquals(2, currRow.size()); 5591 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), 5592 currRow.get(0).getRowLength(), row4, 0, 5593 row4.length)); 5594 assertTrue(hasNext); 5595 // 2. scan out "row3" (2 kv) 5596 currRow.clear(); 5597 hasNext = scanner.next(currRow); 5598 assertEquals(2, currRow.size()); 5599 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5600 .get(0).getRowLength(), row3, 0, row3.length)); 5601 assertTrue(hasNext); 5602 // 3. scan out "row2" (4 kvs) 5603 // "row2" takes 2 next() calls since batch=3 5604 currRow.clear(); 5605 hasNext = scanner.next(currRow); 5606 assertEquals(3, currRow.size()); 5607 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5608 .get(0).getRowLength(), row2, 0, row2.length)); 5609 assertTrue(hasNext); 5610 currRow.clear(); 5611 hasNext = scanner.next(currRow); 5612 assertEquals(1, currRow.size()); 5613 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5614 .get(0).getRowLength(), row2, 0, row2.length)); 5615 assertTrue(hasNext); 5616 // 4. scan out "row1" (2 kv) 5617 currRow.clear(); 5618 hasNext = scanner.next(currRow); 5619 assertEquals(2, currRow.size()); 5620 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5621 .get(0).getRowLength(), row1, 0, row1.length)); 5622 assertTrue(hasNext); 5623 // 5. scan out "row0" (1 kv) 5624 currRow.clear(); 5625 hasNext = scanner.next(currRow); 5626 assertEquals(1, currRow.size()); 5627 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5628 .get(0).getRowLength(), row0, 0, row0.length)); 5629 assertFalse(hasNext); 5630 5631 scanner.close(); 5632 } finally { 5633 HBaseTestingUtility.closeRegionAndWAL(this.region); 5634 this.region = null; 5635 } 5636 } 5637 5638 @Test 5639 public void testReverseScanner_FromMemStoreAndHFiles_MultiCFs2() 5640 throws IOException { 5641 byte[] row1 = Bytes.toBytes("row1"); 5642 byte[] row2 = Bytes.toBytes("row2"); 5643 byte[] row3 = Bytes.toBytes("row3"); 5644 byte[] row4 = Bytes.toBytes("row4"); 5645 byte[] cf1 = Bytes.toBytes("CF1"); 5646 byte[] cf2 = Bytes.toBytes("CF2"); 5647 byte[] cf3 = Bytes.toBytes("CF3"); 5648 byte[] cf4 = Bytes.toBytes("CF4"); 5649 byte[][] families = { cf1, cf2, cf3, cf4 }; 5650 byte[] col = Bytes.toBytes("C"); 5651 long ts = 1; 5652 HBaseConfiguration conf = new HBaseConfiguration(); 5653 // disable compactions in this test. 5654 conf.setInt("hbase.hstore.compactionThreshold", 10000); 5655 this.region = initHRegion(tableName, method, conf, families); 5656 try { 5657 KeyValue kv1 = new KeyValue(row1, cf1, col, ts, KeyValue.Type.Put, null); 5658 KeyValue kv2 = new KeyValue(row2, cf2, col, ts, KeyValue.Type.Put, null); 5659 KeyValue kv3 = new KeyValue(row3, cf3, col, ts, KeyValue.Type.Put, null); 5660 KeyValue kv4 = new KeyValue(row4, cf4, col, ts, KeyValue.Type.Put, null); 5661 // storefile1 5662 Put put = new Put(row1); 5663 put.add(kv1); 5664 region.put(put); 5665 region.flush(true); 5666 // storefile2 5667 put = new Put(row2); 5668 put.add(kv2); 5669 region.put(put); 5670 region.flush(true); 5671 // storefile3 5672 put = new Put(row3); 5673 put.add(kv3); 5674 region.put(put); 5675 region.flush(true); 5676 // memstore 5677 put = new Put(row4); 5678 put.add(kv4); 5679 region.put(put); 5680 // scan range = ["row4", min) 5681 Scan scan = new Scan(row4); 5682 scan.setReversed(true); 5683 scan.setBatch(10); 5684 InternalScanner scanner = region.getScanner(scan); 5685 List<Cell> currRow = new ArrayList<>(); 5686 boolean hasNext = scanner.next(currRow); 5687 assertEquals(1, currRow.size()); 5688 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5689 .get(0).getRowLength(), row4, 0, row4.length)); 5690 assertTrue(hasNext); 5691 currRow.clear(); 5692 hasNext = scanner.next(currRow); 5693 assertEquals(1, currRow.size()); 5694 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5695 .get(0).getRowLength(), row3, 0, row3.length)); 5696 assertTrue(hasNext); 5697 currRow.clear(); 5698 hasNext = scanner.next(currRow); 5699 assertEquals(1, currRow.size()); 5700 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5701 .get(0).getRowLength(), row2, 0, row2.length)); 5702 assertTrue(hasNext); 5703 currRow.clear(); 5704 hasNext = scanner.next(currRow); 5705 assertEquals(1, currRow.size()); 5706 assertTrue(Bytes.equals(currRow.get(0).getRowArray(), currRow.get(0).getRowOffset(), currRow 5707 .get(0).getRowLength(), row1, 0, row1.length)); 5708 assertFalse(hasNext); 5709 } finally { 5710 HBaseTestingUtility.closeRegionAndWAL(this.region); 5711 this.region = null; 5712 } 5713 } 5714 5715 /** 5716 * Test for HBASE-14497: Reverse Scan threw StackOverflow caused by readPt checking 5717 */ 5718 @Test 5719 public void testReverseScanner_StackOverflow() throws IOException { 5720 byte[] cf1 = Bytes.toBytes("CF1"); 5721 byte[][] families = {cf1}; 5722 byte[] col = Bytes.toBytes("C"); 5723 HBaseConfiguration conf = new HBaseConfiguration(); 5724 this.region = initHRegion(tableName, method, conf, families); 5725 try { 5726 // setup with one storefile and one memstore, to create scanner and get an earlier readPt 5727 Put put = new Put(Bytes.toBytes("19998")); 5728 put.addColumn(cf1, col, Bytes.toBytes("val")); 5729 region.put(put); 5730 region.flushcache(true, true, FlushLifeCycleTracker.DUMMY); 5731 Put put2 = new Put(Bytes.toBytes("19997")); 5732 put2.addColumn(cf1, col, Bytes.toBytes("val")); 5733 region.put(put2); 5734 5735 Scan scan = new Scan(Bytes.toBytes("19998")); 5736 scan.setReversed(true); 5737 InternalScanner scanner = region.getScanner(scan); 5738 5739 // create one storefile contains many rows will be skipped 5740 // to check StoreFileScanner.seekToPreviousRow 5741 for (int i = 10000; i < 20000; i++) { 5742 Put p = new Put(Bytes.toBytes(""+i)); 5743 p.addColumn(cf1, col, Bytes.toBytes("" + i)); 5744 region.put(p); 5745 } 5746 region.flushcache(true, true, FlushLifeCycleTracker.DUMMY); 5747 5748 // create one memstore contains many rows will be skipped 5749 // to check MemStoreScanner.seekToPreviousRow 5750 for (int i = 10000; i < 20000; i++) { 5751 Put p = new Put(Bytes.toBytes(""+i)); 5752 p.addColumn(cf1, col, Bytes.toBytes("" + i)); 5753 region.put(p); 5754 } 5755 5756 List<Cell> currRow = new ArrayList<>(); 5757 boolean hasNext; 5758 do { 5759 hasNext = scanner.next(currRow); 5760 } while (hasNext); 5761 assertEquals(2, currRow.size()); 5762 assertEquals("19998", Bytes.toString(currRow.get(0).getRowArray(), 5763 currRow.get(0).getRowOffset(), currRow.get(0).getRowLength())); 5764 assertEquals("19997", Bytes.toString(currRow.get(1).getRowArray(), 5765 currRow.get(1).getRowOffset(), currRow.get(1).getRowLength())); 5766 } finally { 5767 HBaseTestingUtility.closeRegionAndWAL(this.region); 5768 this.region = null; 5769 } 5770 } 5771 5772 @Test 5773 public void testReverseScanShouldNotScanMemstoreIfReadPtLesser() throws Exception { 5774 byte[] cf1 = Bytes.toBytes("CF1"); 5775 byte[][] families = { cf1 }; 5776 byte[] col = Bytes.toBytes("C"); 5777 HBaseConfiguration conf = new HBaseConfiguration(); 5778 this.region = initHRegion(tableName, method, conf, families); 5779 try { 5780 // setup with one storefile and one memstore, to create scanner and get an earlier readPt 5781 Put put = new Put(Bytes.toBytes("19996")); 5782 put.addColumn(cf1, col, Bytes.toBytes("val")); 5783 region.put(put); 5784 Put put2 = new Put(Bytes.toBytes("19995")); 5785 put2.addColumn(cf1, col, Bytes.toBytes("val")); 5786 region.put(put2); 5787 // create a reverse scan 5788 Scan scan = new Scan(Bytes.toBytes("19996")); 5789 scan.setReversed(true); 5790 RegionScannerImpl scanner = region.getScanner(scan); 5791 5792 // flush the cache. This will reset the store scanner 5793 region.flushcache(true, true, FlushLifeCycleTracker.DUMMY); 5794 5795 // create one memstore contains many rows will be skipped 5796 // to check MemStoreScanner.seekToPreviousRow 5797 for (int i = 10000; i < 20000; i++) { 5798 Put p = new Put(Bytes.toBytes("" + i)); 5799 p.addColumn(cf1, col, Bytes.toBytes("" + i)); 5800 region.put(p); 5801 } 5802 List<Cell> currRow = new ArrayList<>(); 5803 boolean hasNext; 5804 boolean assertDone = false; 5805 do { 5806 hasNext = scanner.next(currRow); 5807 // With HBASE-15871, after the scanner is reset the memstore scanner should not be 5808 // added here 5809 if (!assertDone) { 5810 StoreScanner current = 5811 (StoreScanner) (scanner.storeHeap).getCurrentForTesting(); 5812 List<KeyValueScanner> scanners = current.getAllScannersForTesting(); 5813 assertEquals("There should be only one scanner the store file scanner", 1, 5814 scanners.size()); 5815 assertDone = true; 5816 } 5817 } while (hasNext); 5818 assertEquals(2, currRow.size()); 5819 assertEquals("19996", Bytes.toString(currRow.get(0).getRowArray(), 5820 currRow.get(0).getRowOffset(), currRow.get(0).getRowLength())); 5821 assertEquals("19995", Bytes.toString(currRow.get(1).getRowArray(), 5822 currRow.get(1).getRowOffset(), currRow.get(1).getRowLength())); 5823 } finally { 5824 HBaseTestingUtility.closeRegionAndWAL(this.region); 5825 this.region = null; 5826 } 5827 } 5828 5829 @Test 5830 public void testReverseScanWhenPutCellsAfterOpenReverseScan() throws Exception { 5831 byte[] cf1 = Bytes.toBytes("CF1"); 5832 byte[][] families = { cf1 }; 5833 byte[] col = Bytes.toBytes("C"); 5834 5835 HBaseConfiguration conf = new HBaseConfiguration(); 5836 this.region = initHRegion(tableName, method, conf, families); 5837 5838 Put put = new Put(Bytes.toBytes("199996")); 5839 put.addColumn(cf1, col, Bytes.toBytes("val")); 5840 region.put(put); 5841 Put put2 = new Put(Bytes.toBytes("199995")); 5842 put2.addColumn(cf1, col, Bytes.toBytes("val")); 5843 region.put(put2); 5844 5845 // Create a reverse scan 5846 Scan scan = new Scan(Bytes.toBytes("199996")); 5847 scan.setReversed(true); 5848 RegionScannerImpl scanner = region.getScanner(scan); 5849 5850 // Put a lot of cells that have sequenceIDs grater than the readPt of the reverse scan 5851 for (int i = 100000; i < 200000; i++) { 5852 Put p = new Put(Bytes.toBytes("" + i)); 5853 p.addColumn(cf1, col, Bytes.toBytes("" + i)); 5854 region.put(p); 5855 } 5856 List<Cell> currRow = new ArrayList<>(); 5857 boolean hasNext; 5858 do { 5859 hasNext = scanner.next(currRow); 5860 } while (hasNext); 5861 5862 assertEquals(2, currRow.size()); 5863 assertEquals("199996", Bytes.toString(currRow.get(0).getRowArray(), 5864 currRow.get(0).getRowOffset(), currRow.get(0).getRowLength())); 5865 assertEquals("199995", Bytes.toString(currRow.get(1).getRowArray(), 5866 currRow.get(1).getRowOffset(), currRow.get(1).getRowLength())); 5867 } 5868 5869 @Test 5870 public void testWriteRequestsCounter() throws IOException { 5871 byte[] fam = Bytes.toBytes("info"); 5872 byte[][] families = { fam }; 5873 this.region = initHRegion(tableName, method, CONF, families); 5874 5875 Assert.assertEquals(0L, region.getWriteRequestsCount()); 5876 5877 Put put = new Put(row); 5878 put.addColumn(fam, fam, fam); 5879 5880 Assert.assertEquals(0L, region.getWriteRequestsCount()); 5881 region.put(put); 5882 Assert.assertEquals(1L, region.getWriteRequestsCount()); 5883 region.put(put); 5884 Assert.assertEquals(2L, region.getWriteRequestsCount()); 5885 region.put(put); 5886 Assert.assertEquals(3L, region.getWriteRequestsCount()); 5887 5888 region.delete(new Delete(row)); 5889 Assert.assertEquals(4L, region.getWriteRequestsCount()); 5890 5891 HBaseTestingUtility.closeRegionAndWAL(this.region); 5892 this.region = null; 5893 } 5894 5895 @Test 5896 public void testOpenRegionWrittenToWAL() throws Exception { 5897 final ServerName serverName = ServerName.valueOf(name.getMethodName(), 100, 42); 5898 final RegionServerServices rss = spy(TEST_UTIL.createMockRegionServerService(serverName)); 5899 5900 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 5901 htd.addFamily(new HColumnDescriptor(fam1)); 5902 htd.addFamily(new HColumnDescriptor(fam2)); 5903 5904 HRegionInfo hri = new HRegionInfo(htd.getTableName(), 5905 HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY); 5906 5907 // open the region w/o rss and wal and flush some files 5908 HRegion region = 5909 HBaseTestingUtility.createRegionAndWAL(hri, TEST_UTIL.getDataTestDir(), TEST_UTIL 5910 .getConfiguration(), htd); 5911 assertNotNull(region); 5912 5913 // create a file in fam1 for the region before opening in OpenRegionHandler 5914 region.put(new Put(Bytes.toBytes("a")).addColumn(fam1, fam1, fam1)); 5915 region.flush(true); 5916 HBaseTestingUtility.closeRegionAndWAL(region); 5917 5918 ArgumentCaptor<WALEdit> editCaptor = ArgumentCaptor.forClass(WALEdit.class); 5919 5920 // capture append() calls 5921 WAL wal = mockWAL(); 5922 when(rss.getWAL((HRegionInfo) any())).thenReturn(wal); 5923 5924 try { 5925 region = HRegion.openHRegion(hri, htd, rss.getWAL(hri), 5926 TEST_UTIL.getConfiguration(), rss, null); 5927 5928 verify(wal, times(1)).append((HRegionInfo)any(), (WALKeyImpl)any() 5929 , editCaptor.capture(), anyBoolean()); 5930 5931 WALEdit edit = editCaptor.getValue(); 5932 assertNotNull(edit); 5933 assertNotNull(edit.getCells()); 5934 assertEquals(1, edit.getCells().size()); 5935 RegionEventDescriptor desc = WALEdit.getRegionEventDescriptor(edit.getCells().get(0)); 5936 assertNotNull(desc); 5937 5938 LOG.info("RegionEventDescriptor from WAL: " + desc); 5939 5940 assertEquals(RegionEventDescriptor.EventType.REGION_OPEN, desc.getEventType()); 5941 assertTrue(Bytes.equals(desc.getTableName().toByteArray(), htd.getTableName().toBytes())); 5942 assertTrue(Bytes.equals(desc.getEncodedRegionName().toByteArray(), 5943 hri.getEncodedNameAsBytes())); 5944 assertTrue(desc.getLogSequenceNumber() > 0); 5945 assertEquals(serverName, ProtobufUtil.toServerName(desc.getServer())); 5946 assertEquals(2, desc.getStoresCount()); 5947 5948 StoreDescriptor store = desc.getStores(0); 5949 assertTrue(Bytes.equals(store.getFamilyName().toByteArray(), fam1)); 5950 assertEquals(store.getStoreHomeDir(), Bytes.toString(fam1)); 5951 assertEquals(1, store.getStoreFileCount()); // 1store file 5952 assertFalse(store.getStoreFile(0).contains("/")); // ensure path is relative 5953 5954 store = desc.getStores(1); 5955 assertTrue(Bytes.equals(store.getFamilyName().toByteArray(), fam2)); 5956 assertEquals(store.getStoreHomeDir(), Bytes.toString(fam2)); 5957 assertEquals(0, store.getStoreFileCount()); // no store files 5958 5959 } finally { 5960 HBaseTestingUtility.closeRegionAndWAL(region); 5961 } 5962 } 5963 5964 // Helper for test testOpenRegionWrittenToWALForLogReplay 5965 static class HRegionWithSeqId extends HRegion { 5966 public HRegionWithSeqId(final Path tableDir, final WAL wal, final FileSystem fs, 5967 final Configuration confParam, final RegionInfo regionInfo, 5968 final TableDescriptor htd, final RegionServerServices rsServices) { 5969 super(tableDir, wal, fs, confParam, regionInfo, htd, rsServices); 5970 } 5971 @Override 5972 protected long getNextSequenceId(WAL wal) throws IOException { 5973 return 42; 5974 } 5975 } 5976 5977 @Test 5978 public void testFlushedFileWithNoTags() throws Exception { 5979 final TableName tableName = TableName.valueOf(name.getMethodName()); 5980 HTableDescriptor htd = new HTableDescriptor(tableName); 5981 htd.addFamily(new HColumnDescriptor(fam1)); 5982 HRegionInfo info = new HRegionInfo(tableName, null, null, false); 5983 Path path = TEST_UTIL.getDataTestDir(getClass().getSimpleName()); 5984 region = HBaseTestingUtility.createRegionAndWAL(info, path, TEST_UTIL.getConfiguration(), htd); 5985 Put put = new Put(Bytes.toBytes("a-b-0-0")); 5986 put.addColumn(fam1, qual1, Bytes.toBytes("c1-value")); 5987 region.put(put); 5988 region.flush(true); 5989 HStore store = region.getStore(fam1); 5990 Collection<HStoreFile> storefiles = store.getStorefiles(); 5991 for (HStoreFile sf : storefiles) { 5992 assertFalse("Tags should not be present " 5993 ,sf.getReader().getHFileReader().getFileContext().isIncludesTags()); 5994 } 5995 } 5996 5997 /** 5998 * Utility method to setup a WAL mock. 5999 * Needs to do the bit where we close latch on the WALKeyImpl on append else test hangs. 6000 * @return 6001 * @throws IOException 6002 */ 6003 private WAL mockWAL() throws IOException { 6004 WAL wal = mock(WAL.class); 6005 Mockito.when(wal.append((HRegionInfo)Mockito.any(), 6006 (WALKeyImpl)Mockito.any(), (WALEdit)Mockito.any(), Mockito.anyBoolean())). 6007 thenAnswer(new Answer<Long>() { 6008 @Override 6009 public Long answer(InvocationOnMock invocation) throws Throwable { 6010 WALKeyImpl key = invocation.getArgument(1); 6011 MultiVersionConcurrencyControl.WriteEntry we = key.getMvcc().begin(); 6012 key.setWriteEntry(we); 6013 return 1L; 6014 } 6015 6016 }); 6017 return wal; 6018 } 6019 6020 @Test 6021 public void testCloseRegionWrittenToWAL() throws Exception { 6022 6023 Path rootDir = new Path(dir + name.getMethodName()); 6024 FSUtils.setRootDir(TEST_UTIL.getConfiguration(), rootDir); 6025 6026 final ServerName serverName = ServerName.valueOf("testCloseRegionWrittenToWAL", 100, 42); 6027 final RegionServerServices rss = spy(TEST_UTIL.createMockRegionServerService(serverName)); 6028 6029 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 6030 htd.addFamily(new HColumnDescriptor(fam1)); 6031 htd.addFamily(new HColumnDescriptor(fam2)); 6032 6033 final HRegionInfo hri = new HRegionInfo(htd.getTableName(), 6034 HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY); 6035 6036 ArgumentCaptor<WALEdit> editCaptor = ArgumentCaptor.forClass(WALEdit.class); 6037 6038 // capture append() calls 6039 WAL wal = mockWAL(); 6040 when(rss.getWAL((HRegionInfo) any())).thenReturn(wal); 6041 6042 6043 // create and then open a region first so that it can be closed later 6044 region = HRegion.createHRegion(hri, rootDir, TEST_UTIL.getConfiguration(), htd, rss.getWAL(hri)); 6045 region = HRegion.openHRegion(hri, htd, rss.getWAL(hri), 6046 TEST_UTIL.getConfiguration(), rss, null); 6047 6048 // close the region 6049 region.close(false); 6050 6051 // 2 times, one for region open, the other close region 6052 verify(wal, times(2)).append((HRegionInfo)any(), (WALKeyImpl)any(), 6053 editCaptor.capture(), anyBoolean()); 6054 6055 WALEdit edit = editCaptor.getAllValues().get(1); 6056 assertNotNull(edit); 6057 assertNotNull(edit.getCells()); 6058 assertEquals(1, edit.getCells().size()); 6059 RegionEventDescriptor desc = WALEdit.getRegionEventDescriptor(edit.getCells().get(0)); 6060 assertNotNull(desc); 6061 6062 LOG.info("RegionEventDescriptor from WAL: " + desc); 6063 6064 assertEquals(RegionEventDescriptor.EventType.REGION_CLOSE, desc.getEventType()); 6065 assertTrue(Bytes.equals(desc.getTableName().toByteArray(), htd.getTableName().toBytes())); 6066 assertTrue(Bytes.equals(desc.getEncodedRegionName().toByteArray(), 6067 hri.getEncodedNameAsBytes())); 6068 assertTrue(desc.getLogSequenceNumber() > 0); 6069 assertEquals(serverName, ProtobufUtil.toServerName(desc.getServer())); 6070 assertEquals(2, desc.getStoresCount()); 6071 6072 StoreDescriptor store = desc.getStores(0); 6073 assertTrue(Bytes.equals(store.getFamilyName().toByteArray(), fam1)); 6074 assertEquals(store.getStoreHomeDir(), Bytes.toString(fam1)); 6075 assertEquals(0, store.getStoreFileCount()); // no store files 6076 6077 store = desc.getStores(1); 6078 assertTrue(Bytes.equals(store.getFamilyName().toByteArray(), fam2)); 6079 assertEquals(store.getStoreHomeDir(), Bytes.toString(fam2)); 6080 assertEquals(0, store.getStoreFileCount()); // no store files 6081 } 6082 6083 /** 6084 * Test RegionTooBusyException thrown when region is busy 6085 */ 6086 @Test 6087 public void testRegionTooBusy() throws IOException { 6088 byte[] family = Bytes.toBytes("family"); 6089 long defaultBusyWaitDuration = CONF.getLong("hbase.busy.wait.duration", 6090 HRegion.DEFAULT_BUSY_WAIT_DURATION); 6091 CONF.setLong("hbase.busy.wait.duration", 1000); 6092 region = initHRegion(tableName, method, CONF, family); 6093 final AtomicBoolean stopped = new AtomicBoolean(true); 6094 Thread t = new Thread(new Runnable() { 6095 @Override 6096 public void run() { 6097 try { 6098 region.lock.writeLock().lock(); 6099 stopped.set(false); 6100 while (!stopped.get()) { 6101 Thread.sleep(100); 6102 } 6103 } catch (InterruptedException ie) { 6104 } finally { 6105 region.lock.writeLock().unlock(); 6106 } 6107 } 6108 }); 6109 t.start(); 6110 Get get = new Get(row); 6111 try { 6112 while (stopped.get()) { 6113 Thread.sleep(100); 6114 } 6115 region.get(get); 6116 fail("Should throw RegionTooBusyException"); 6117 } catch (InterruptedException ie) { 6118 fail("test interrupted"); 6119 } catch (RegionTooBusyException e) { 6120 // Good, expected 6121 } finally { 6122 stopped.set(true); 6123 try { 6124 t.join(); 6125 } catch (Throwable e) { 6126 } 6127 6128 HBaseTestingUtility.closeRegionAndWAL(region); 6129 region = null; 6130 CONF.setLong("hbase.busy.wait.duration", defaultBusyWaitDuration); 6131 } 6132 } 6133 6134 @Test 6135 public void testCellTTLs() throws IOException { 6136 IncrementingEnvironmentEdge edge = new IncrementingEnvironmentEdge(); 6137 EnvironmentEdgeManager.injectEdge(edge); 6138 6139 final byte[] row = Bytes.toBytes("testRow"); 6140 final byte[] q1 = Bytes.toBytes("q1"); 6141 final byte[] q2 = Bytes.toBytes("q2"); 6142 final byte[] q3 = Bytes.toBytes("q3"); 6143 final byte[] q4 = Bytes.toBytes("q4"); 6144 6145 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 6146 HColumnDescriptor hcd = new HColumnDescriptor(fam1); 6147 hcd.setTimeToLive(10); // 10 seconds 6148 htd.addFamily(hcd); 6149 6150 Configuration conf = new Configuration(TEST_UTIL.getConfiguration()); 6151 conf.setInt(HFile.FORMAT_VERSION_KEY, HFile.MIN_FORMAT_VERSION_WITH_TAGS); 6152 6153 HRegion region = HBaseTestingUtility.createRegionAndWAL(new HRegionInfo(htd.getTableName(), 6154 HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY), 6155 TEST_UTIL.getDataTestDir(), conf, htd); 6156 assertNotNull(region); 6157 try { 6158 long now = EnvironmentEdgeManager.currentTime(); 6159 // Add a cell that will expire in 5 seconds via cell TTL 6160 region.put(new Put(row).add(new KeyValue(row, fam1, q1, now, 6161 HConstants.EMPTY_BYTE_ARRAY, new ArrayBackedTag[] { 6162 // TTL tags specify ts in milliseconds 6163 new ArrayBackedTag(TagType.TTL_TAG_TYPE, Bytes.toBytes(5000L)) } ))); 6164 // Add a cell that will expire after 10 seconds via family setting 6165 region.put(new Put(row).addColumn(fam1, q2, now, HConstants.EMPTY_BYTE_ARRAY)); 6166 // Add a cell that will expire in 15 seconds via cell TTL 6167 region.put(new Put(row).add(new KeyValue(row, fam1, q3, now + 10000 - 1, 6168 HConstants.EMPTY_BYTE_ARRAY, new ArrayBackedTag[] { 6169 // TTL tags specify ts in milliseconds 6170 new ArrayBackedTag(TagType.TTL_TAG_TYPE, Bytes.toBytes(5000L)) } ))); 6171 // Add a cell that will expire in 20 seconds via family setting 6172 region.put(new Put(row).addColumn(fam1, q4, now + 10000 - 1, HConstants.EMPTY_BYTE_ARRAY)); 6173 6174 // Flush so we are sure store scanning gets this right 6175 region.flush(true); 6176 6177 // A query at time T+0 should return all cells 6178 Result r = region.get(new Get(row)); 6179 assertNotNull(r.getValue(fam1, q1)); 6180 assertNotNull(r.getValue(fam1, q2)); 6181 assertNotNull(r.getValue(fam1, q3)); 6182 assertNotNull(r.getValue(fam1, q4)); 6183 6184 // Increment time to T+5 seconds 6185 edge.incrementTime(5000); 6186 6187 r = region.get(new Get(row)); 6188 assertNull(r.getValue(fam1, q1)); 6189 assertNotNull(r.getValue(fam1, q2)); 6190 assertNotNull(r.getValue(fam1, q3)); 6191 assertNotNull(r.getValue(fam1, q4)); 6192 6193 // Increment time to T+10 seconds 6194 edge.incrementTime(5000); 6195 6196 r = region.get(new Get(row)); 6197 assertNull(r.getValue(fam1, q1)); 6198 assertNull(r.getValue(fam1, q2)); 6199 assertNotNull(r.getValue(fam1, q3)); 6200 assertNotNull(r.getValue(fam1, q4)); 6201 6202 // Increment time to T+15 seconds 6203 edge.incrementTime(5000); 6204 6205 r = region.get(new Get(row)); 6206 assertNull(r.getValue(fam1, q1)); 6207 assertNull(r.getValue(fam1, q2)); 6208 assertNull(r.getValue(fam1, q3)); 6209 assertNotNull(r.getValue(fam1, q4)); 6210 6211 // Increment time to T+20 seconds 6212 edge.incrementTime(10000); 6213 6214 r = region.get(new Get(row)); 6215 assertNull(r.getValue(fam1, q1)); 6216 assertNull(r.getValue(fam1, q2)); 6217 assertNull(r.getValue(fam1, q3)); 6218 assertNull(r.getValue(fam1, q4)); 6219 6220 // Fun with disappearing increments 6221 6222 // Start at 1 6223 region.put(new Put(row).addColumn(fam1, q1, Bytes.toBytes(1L))); 6224 r = region.get(new Get(row)); 6225 byte[] val = r.getValue(fam1, q1); 6226 assertNotNull(val); 6227 assertEquals(1L, Bytes.toLong(val)); 6228 6229 // Increment with a TTL of 5 seconds 6230 Increment incr = new Increment(row).addColumn(fam1, q1, 1L); 6231 incr.setTTL(5000); 6232 region.increment(incr); // 2 6233 6234 // New value should be 2 6235 r = region.get(new Get(row)); 6236 val = r.getValue(fam1, q1); 6237 assertNotNull(val); 6238 assertEquals(2L, Bytes.toLong(val)); 6239 6240 // Increment time to T+25 seconds 6241 edge.incrementTime(5000); 6242 6243 // Value should be back to 1 6244 r = region.get(new Get(row)); 6245 val = r.getValue(fam1, q1); 6246 assertNotNull(val); 6247 assertEquals(1L, Bytes.toLong(val)); 6248 6249 // Increment time to T+30 seconds 6250 edge.incrementTime(5000); 6251 6252 // Original value written at T+20 should be gone now via family TTL 6253 r = region.get(new Get(row)); 6254 assertNull(r.getValue(fam1, q1)); 6255 6256 } finally { 6257 HBaseTestingUtility.closeRegionAndWAL(region); 6258 } 6259 } 6260 6261 @Test 6262 public void testIncrementTimestampsAreMonotonic() throws IOException { 6263 HRegion region = initHRegion(tableName, method, CONF, fam1); 6264 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 6265 EnvironmentEdgeManager.injectEdge(edge); 6266 6267 edge.setValue(10); 6268 Increment inc = new Increment(row); 6269 inc.setDurability(Durability.SKIP_WAL); 6270 inc.addColumn(fam1, qual1, 1L); 6271 region.increment(inc); 6272 6273 Result result = region.get(new Get(row)); 6274 Cell c = result.getColumnLatestCell(fam1, qual1); 6275 assertNotNull(c); 6276 assertEquals(10L, c.getTimestamp()); 6277 6278 edge.setValue(1); // clock goes back 6279 region.increment(inc); 6280 result = region.get(new Get(row)); 6281 c = result.getColumnLatestCell(fam1, qual1); 6282 assertEquals(11L, c.getTimestamp()); 6283 assertEquals(2L, Bytes.toLong(c.getValueArray(), c.getValueOffset(), c.getValueLength())); 6284 } 6285 6286 @Test 6287 public void testAppendTimestampsAreMonotonic() throws IOException { 6288 HRegion region = initHRegion(tableName, method, CONF, fam1); 6289 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 6290 EnvironmentEdgeManager.injectEdge(edge); 6291 6292 edge.setValue(10); 6293 Append a = new Append(row); 6294 a.setDurability(Durability.SKIP_WAL); 6295 a.addColumn(fam1, qual1, qual1); 6296 region.append(a); 6297 6298 Result result = region.get(new Get(row)); 6299 Cell c = result.getColumnLatestCell(fam1, qual1); 6300 assertNotNull(c); 6301 assertEquals(10L, c.getTimestamp()); 6302 6303 edge.setValue(1); // clock goes back 6304 region.append(a); 6305 result = region.get(new Get(row)); 6306 c = result.getColumnLatestCell(fam1, qual1); 6307 assertEquals(11L, c.getTimestamp()); 6308 6309 byte[] expected = new byte[qual1.length*2]; 6310 System.arraycopy(qual1, 0, expected, 0, qual1.length); 6311 System.arraycopy(qual1, 0, expected, qual1.length, qual1.length); 6312 6313 assertTrue(Bytes.equals(c.getValueArray(), c.getValueOffset(), c.getValueLength(), 6314 expected, 0, expected.length)); 6315 } 6316 6317 @Test 6318 public void testCheckAndMutateTimestampsAreMonotonic() throws IOException { 6319 HRegion region = initHRegion(tableName, method, CONF, fam1); 6320 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 6321 EnvironmentEdgeManager.injectEdge(edge); 6322 6323 edge.setValue(10); 6324 Put p = new Put(row); 6325 p.setDurability(Durability.SKIP_WAL); 6326 p.addColumn(fam1, qual1, qual1); 6327 region.put(p); 6328 6329 Result result = region.get(new Get(row)); 6330 Cell c = result.getColumnLatestCell(fam1, qual1); 6331 assertNotNull(c); 6332 assertEquals(10L, c.getTimestamp()); 6333 6334 edge.setValue(1); // clock goes back 6335 p = new Put(row); 6336 p.setDurability(Durability.SKIP_WAL); 6337 p.addColumn(fam1, qual1, qual2); 6338 region.checkAndMutate(row, fam1, qual1, CompareOperator.EQUAL, new BinaryComparator(qual1), p); 6339 result = region.get(new Get(row)); 6340 c = result.getColumnLatestCell(fam1, qual1); 6341 assertEquals(10L, c.getTimestamp()); 6342 6343 assertTrue(Bytes.equals(c.getValueArray(), c.getValueOffset(), c.getValueLength(), 6344 qual2, 0, qual2.length)); 6345 } 6346 6347 @Test 6348 public void testBatchMutateWithWrongRegionException() throws Exception { 6349 final byte[] a = Bytes.toBytes("a"); 6350 final byte[] b = Bytes.toBytes("b"); 6351 final byte[] c = Bytes.toBytes("c"); // exclusive 6352 6353 int prevLockTimeout = CONF.getInt("hbase.rowlock.wait.duration", 30000); 6354 CONF.setInt("hbase.rowlock.wait.duration", 1000); 6355 final HRegion region = initHRegion(tableName, a, c, method, CONF, false, fam1); 6356 6357 Mutation[] mutations = new Mutation[] { 6358 new Put(a) 6359 .add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 6360 .setRow(a) 6361 .setFamily(fam1) 6362 .setTimestamp(HConstants.LATEST_TIMESTAMP) 6363 .setType(Cell.Type.Put) 6364 .build()), 6365 // this is outside the region boundary 6366 new Put(c).add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 6367 .setRow(c) 6368 .setFamily(fam1) 6369 .setTimestamp(HConstants.LATEST_TIMESTAMP) 6370 .setType(Type.Put) 6371 .build()), 6372 new Put(b).add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 6373 .setRow(b) 6374 .setFamily(fam1) 6375 .setTimestamp(HConstants.LATEST_TIMESTAMP) 6376 .setType(Cell.Type.Put) 6377 .build()) 6378 }; 6379 6380 OperationStatus[] status = region.batchMutate(mutations); 6381 assertEquals(OperationStatusCode.SUCCESS, status[0].getOperationStatusCode()); 6382 assertEquals(OperationStatusCode.SANITY_CHECK_FAILURE, status[1].getOperationStatusCode()); 6383 assertEquals(OperationStatusCode.SUCCESS, status[2].getOperationStatusCode()); 6384 6385 6386 // test with a row lock held for a long time 6387 final CountDownLatch obtainedRowLock = new CountDownLatch(1); 6388 ExecutorService exec = Executors.newFixedThreadPool(2); 6389 Future<Void> f1 = exec.submit(new Callable<Void>() { 6390 @Override 6391 public Void call() throws Exception { 6392 LOG.info("Acquiring row lock"); 6393 RowLock rl = region.getRowLock(b); 6394 obtainedRowLock.countDown(); 6395 LOG.info("Waiting for 5 seconds before releasing lock"); 6396 Threads.sleep(5000); 6397 LOG.info("Releasing row lock"); 6398 rl.release(); 6399 return null; 6400 } 6401 }); 6402 obtainedRowLock.await(30, TimeUnit.SECONDS); 6403 6404 Future<Void> f2 = exec.submit(new Callable<Void>() { 6405 @Override 6406 public Void call() throws Exception { 6407 Mutation[] mutations = new Mutation[] { 6408 new Put(a).add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 6409 .setRow(a) 6410 .setFamily(fam1) 6411 .setTimestamp(HConstants.LATEST_TIMESTAMP) 6412 .setType(Cell.Type.Put) 6413 .build()), 6414 new Put(b).add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY) 6415 .setRow(b) 6416 .setFamily(fam1) 6417 .setTimestamp(HConstants.LATEST_TIMESTAMP) 6418 .setType(Cell.Type.Put) 6419 .build()), 6420 }; 6421 6422 // this will wait for the row lock, and it will eventually succeed 6423 OperationStatus[] status = region.batchMutate(mutations); 6424 assertEquals(OperationStatusCode.SUCCESS, status[0].getOperationStatusCode()); 6425 assertEquals(OperationStatusCode.SUCCESS, status[1].getOperationStatusCode()); 6426 return null; 6427 } 6428 }); 6429 6430 f1.get(); 6431 f2.get(); 6432 6433 CONF.setInt("hbase.rowlock.wait.duration", prevLockTimeout); 6434 } 6435 6436 @Test 6437 public void testCheckAndRowMutateTimestampsAreMonotonic() throws IOException { 6438 HRegion region = initHRegion(tableName, method, CONF, fam1); 6439 ManualEnvironmentEdge edge = new ManualEnvironmentEdge(); 6440 EnvironmentEdgeManager.injectEdge(edge); 6441 6442 edge.setValue(10); 6443 Put p = new Put(row); 6444 p.setDurability(Durability.SKIP_WAL); 6445 p.addColumn(fam1, qual1, qual1); 6446 region.put(p); 6447 6448 Result result = region.get(new Get(row)); 6449 Cell c = result.getColumnLatestCell(fam1, qual1); 6450 assertNotNull(c); 6451 assertEquals(10L, c.getTimestamp()); 6452 6453 edge.setValue(1); // clock goes back 6454 p = new Put(row); 6455 p.setDurability(Durability.SKIP_WAL); 6456 p.addColumn(fam1, qual1, qual2); 6457 RowMutations rm = new RowMutations(row); 6458 rm.add(p); 6459 assertTrue(region.checkAndRowMutate(row, fam1, qual1, CompareOperator.EQUAL, 6460 new BinaryComparator(qual1), rm)); 6461 result = region.get(new Get(row)); 6462 c = result.getColumnLatestCell(fam1, qual1); 6463 assertEquals(10L, c.getTimestamp()); 6464 LOG.info("c value " + 6465 Bytes.toStringBinary(c.getValueArray(), c.getValueOffset(), c.getValueLength())); 6466 6467 assertTrue(Bytes.equals(c.getValueArray(), c.getValueOffset(), c.getValueLength(), 6468 qual2, 0, qual2.length)); 6469 } 6470 6471 HRegion initHRegion(TableName tableName, String callingMethod, 6472 byte[]... families) throws IOException { 6473 return initHRegion(tableName, callingMethod, HBaseConfiguration.create(), 6474 families); 6475 } 6476 6477 /** 6478 * HBASE-16429 Make sure no stuck if roll writer when ring buffer is filled with appends 6479 * @throws IOException if IO error occurred during test 6480 */ 6481 @Test 6482 public void testWritesWhileRollWriter() throws IOException { 6483 int testCount = 10; 6484 int numRows = 1024; 6485 int numFamilies = 2; 6486 int numQualifiers = 2; 6487 final byte[][] families = new byte[numFamilies][]; 6488 for (int i = 0; i < numFamilies; i++) { 6489 families[i] = Bytes.toBytes("family" + i); 6490 } 6491 final byte[][] qualifiers = new byte[numQualifiers][]; 6492 for (int i = 0; i < numQualifiers; i++) { 6493 qualifiers[i] = Bytes.toBytes("qual" + i); 6494 } 6495 6496 CONF.setInt("hbase.regionserver.wal.disruptor.event.count", 2); 6497 this.region = initHRegion(tableName, method, CONF, families); 6498 try { 6499 List<Thread> threads = new ArrayList<>(); 6500 for (int i = 0; i < numRows; i++) { 6501 final int count = i; 6502 Thread t = new Thread(new Runnable() { 6503 6504 @Override 6505 public void run() { 6506 byte[] row = Bytes.toBytes("row" + count); 6507 Put put = new Put(row); 6508 put.setDurability(Durability.SYNC_WAL); 6509 byte[] value = Bytes.toBytes(String.valueOf(count)); 6510 for (byte[] family : families) { 6511 for (byte[] qualifier : qualifiers) { 6512 put.addColumn(family, qualifier, count, value); 6513 } 6514 } 6515 try { 6516 region.put(put); 6517 } catch (IOException e) { 6518 throw new RuntimeException(e); 6519 } 6520 } 6521 }); 6522 threads.add(t); 6523 } 6524 for (Thread t : threads) { 6525 t.start(); 6526 } 6527 6528 for (int i = 0; i < testCount; i++) { 6529 region.getWAL().rollWriter(); 6530 Thread.yield(); 6531 } 6532 } finally { 6533 try { 6534 HBaseTestingUtility.closeRegionAndWAL(this.region); 6535 CONF.setInt("hbase.regionserver.wal.disruptor.event.count", 16 * 1024); 6536 } catch (DroppedSnapshotException dse) { 6537 // We could get this on way out because we interrupt the background flusher and it could 6538 // fail anywhere causing a DSE over in the background flusher... only it is not properly 6539 // dealt with so could still be memory hanging out when we get to here -- memory we can't 6540 // flush because the accounting is 'off' since original DSE. 6541 } 6542 this.region = null; 6543 } 6544 } 6545 6546 @Test 6547 public void testMutateRow_WriteRequestCount() throws Exception { 6548 byte[] row1 = Bytes.toBytes("row1"); 6549 byte[] fam1 = Bytes.toBytes("fam1"); 6550 byte[] qf1 = Bytes.toBytes("qualifier"); 6551 byte[] val1 = Bytes.toBytes("value1"); 6552 6553 RowMutations rm = new RowMutations(row1); 6554 Put put = new Put(row1); 6555 put.addColumn(fam1, qf1, val1); 6556 rm.add(put); 6557 6558 this.region = initHRegion(tableName, method, CONF, fam1); 6559 try { 6560 long wrcBeforeMutate = this.region.writeRequestsCount.longValue(); 6561 this.region.mutateRow(rm); 6562 long wrcAfterMutate = this.region.writeRequestsCount.longValue(); 6563 Assert.assertEquals(wrcBeforeMutate + rm.getMutations().size(), wrcAfterMutate); 6564 } finally { 6565 HBaseTestingUtility.closeRegionAndWAL(this.region); 6566 this.region = null; 6567 } 6568 } 6569 6570 @Test 6571 public void testBulkLoadReplicationEnabled() throws IOException { 6572 TEST_UTIL.getConfiguration().setBoolean(HConstants.REPLICATION_BULKLOAD_ENABLE_KEY, true); 6573 final ServerName serverName = ServerName.valueOf(name.getMethodName(), 100, 42); 6574 final RegionServerServices rss = spy(TEST_UTIL.createMockRegionServerService(serverName)); 6575 6576 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName())); 6577 htd.addFamily(new HColumnDescriptor(fam1)); 6578 HRegionInfo hri = new HRegionInfo(htd.getTableName(), 6579 HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY); 6580 region = HRegion.openHRegion(hri, htd, rss.getWAL(hri), TEST_UTIL.getConfiguration(), 6581 rss, null); 6582 6583 assertTrue(region.conf.getBoolean(HConstants.REPLICATION_BULKLOAD_ENABLE_KEY, false)); 6584 String plugins = region.conf.get(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, ""); 6585 String replicationCoprocessorClass = ReplicationObserver.class.getCanonicalName(); 6586 assertTrue(plugins.contains(replicationCoprocessorClass)); 6587 assertTrue(region.getCoprocessorHost(). 6588 getCoprocessors().contains(ReplicationObserver.class.getSimpleName())); 6589 6590 region.close(); 6591 } 6592 6593 /** 6594 * The same as HRegion class, the only difference is that instantiateHStore will 6595 * create a different HStore - HStoreForTesting. [HBASE-8518] 6596 */ 6597 public static class HRegionForTesting extends HRegion { 6598 6599 public HRegionForTesting(final Path tableDir, final WAL wal, final FileSystem fs, 6600 final Configuration confParam, final RegionInfo regionInfo, 6601 final TableDescriptor htd, final RegionServerServices rsServices) { 6602 this(new HRegionFileSystem(confParam, fs, tableDir, regionInfo), 6603 wal, confParam, htd, rsServices); 6604 } 6605 6606 public HRegionForTesting(HRegionFileSystem fs, WAL wal, 6607 Configuration confParam, TableDescriptor htd, 6608 RegionServerServices rsServices) { 6609 super(fs, wal, confParam, htd, rsServices); 6610 } 6611 6612 /** 6613 * Create HStore instance. 6614 * @return If Mob is enabled, return HMobStore, otherwise return HStoreForTesting. 6615 */ 6616 @Override 6617 protected HStore instantiateHStore(final ColumnFamilyDescriptor family) throws IOException { 6618 if (family.isMobEnabled()) { 6619 if (HFile.getFormatVersion(this.conf) < HFile.MIN_FORMAT_VERSION_WITH_TAGS) { 6620 throw new IOException("A minimum HFile version of " 6621 + HFile.MIN_FORMAT_VERSION_WITH_TAGS 6622 + " is required for MOB feature. Consider setting " + HFile.FORMAT_VERSION_KEY 6623 + " accordingly."); 6624 } 6625 return new HMobStore(this, family, this.conf); 6626 } 6627 return new HStoreForTesting(this, family, this.conf); 6628 } 6629 } 6630 6631 /** 6632 * HStoreForTesting is merely the same as HStore, the difference is in the doCompaction method 6633 * of HStoreForTesting there is a checkpoint "hbase.hstore.compaction.complete" which 6634 * doesn't let hstore compaction complete. In the former edition, this config is set in 6635 * HStore class inside compact method, though this is just for testing, otherwise it 6636 * doesn't do any help. In HBASE-8518, we try to get rid of all "hbase.hstore.compaction.complete" 6637 * config (except for testing code). 6638 */ 6639 public static class HStoreForTesting extends HStore { 6640 6641 protected HStoreForTesting(final HRegion region, 6642 final ColumnFamilyDescriptor family, 6643 final Configuration confParam) throws IOException { 6644 super(region, family, confParam); 6645 } 6646 6647 @Override 6648 protected List<HStoreFile> doCompaction(CompactionRequestImpl cr, 6649 Collection<HStoreFile> filesToCompact, User user, long compactionStartTime, 6650 List<Path> newFiles) throws IOException { 6651 // let compaction incomplete. 6652 if (!this.conf.getBoolean("hbase.hstore.compaction.complete", true)) { 6653 LOG.warn("hbase.hstore.compaction.complete is set to false"); 6654 List<HStoreFile> sfs = new ArrayList<>(newFiles.size()); 6655 final boolean evictOnClose = 6656 cacheConf != null? cacheConf.shouldEvictOnClose(): true; 6657 for (Path newFile : newFiles) { 6658 // Create storefile around what we wrote with a reader on it. 6659 HStoreFile sf = createStoreFileAndReader(newFile); 6660 sf.closeStoreFile(evictOnClose); 6661 sfs.add(sf); 6662 } 6663 return sfs; 6664 } 6665 return super.doCompaction(cr, filesToCompact, user, compactionStartTime, newFiles); 6666 } 6667 } 6668}