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