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