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.regionserver.TestHRegion.assertGet; 021import static org.apache.hadoop.hbase.regionserver.TestHRegion.putData; 022import static org.apache.hadoop.hbase.regionserver.TestHRegion.verifyData; 023import static org.junit.jupiter.api.Assertions.assertEquals; 024import static org.junit.jupiter.api.Assertions.assertFalse; 025import static org.junit.jupiter.api.Assertions.assertNotNull; 026import static org.junit.jupiter.api.Assertions.assertNull; 027import static org.junit.jupiter.api.Assertions.assertTrue; 028import static org.junit.jupiter.api.Assertions.fail; 029import static org.mockito.ArgumentMatchers.any; 030import static org.mockito.Mockito.mock; 031import static org.mockito.Mockito.spy; 032import static org.mockito.Mockito.times; 033import static org.mockito.Mockito.verify; 034import static org.mockito.Mockito.when; 035 036import java.io.FileNotFoundException; 037import java.io.IOException; 038import java.util.ArrayList; 039import java.util.List; 040import java.util.Map; 041import java.util.Objects; 042import org.apache.hadoop.conf.Configuration; 043import org.apache.hadoop.fs.FSDataOutputStream; 044import org.apache.hadoop.fs.Path; 045import org.apache.hadoop.hbase.Cell; 046import org.apache.hadoop.hbase.CellBuilderType; 047import org.apache.hadoop.hbase.CellUtil; 048import org.apache.hadoop.hbase.ExtendedCellBuilderFactory; 049import org.apache.hadoop.hbase.HBaseTestingUtil; 050import org.apache.hadoop.hbase.HConstants; 051import org.apache.hadoop.hbase.KeyValue; 052import org.apache.hadoop.hbase.ServerName; 053import org.apache.hadoop.hbase.TableName; 054import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 055import org.apache.hadoop.hbase.client.Durability; 056import org.apache.hadoop.hbase.client.Get; 057import org.apache.hadoop.hbase.client.Put; 058import org.apache.hadoop.hbase.client.RegionInfo; 059import org.apache.hadoop.hbase.client.RegionInfoBuilder; 060import org.apache.hadoop.hbase.client.TableDescriptor; 061import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 062import org.apache.hadoop.hbase.executor.ExecutorService; 063import org.apache.hadoop.hbase.executor.ExecutorType; 064import org.apache.hadoop.hbase.io.hfile.HFile; 065import org.apache.hadoop.hbase.io.hfile.HFileContextBuilder; 066import org.apache.hadoop.hbase.regionserver.HRegion.FlushResultImpl; 067import org.apache.hadoop.hbase.regionserver.HRegion.PrepareFlushResult; 068import org.apache.hadoop.hbase.regionserver.throttle.NoLimitThroughputController; 069import org.apache.hadoop.hbase.testclassification.LargeTests; 070import org.apache.hadoop.hbase.util.Bytes; 071import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 072import org.apache.hadoop.hbase.util.EnvironmentEdgeManagerTestHelper; 073import org.apache.hadoop.hbase.util.FSUtils; 074import org.apache.hadoop.hbase.util.Pair; 075import org.apache.hadoop.hbase.util.Strings; 076import org.apache.hadoop.hbase.wal.AbstractFSWALProvider; 077import org.apache.hadoop.hbase.wal.NoEOFWALStreamReader; 078import org.apache.hadoop.hbase.wal.WAL; 079import org.apache.hadoop.hbase.wal.WALEdit; 080import org.apache.hadoop.hbase.wal.WALFactory; 081import org.apache.hadoop.hbase.wal.WALKeyImpl; 082import org.apache.hadoop.hbase.wal.WALSplitUtil.MutationReplay; 083import org.apache.hadoop.hbase.wal.WALStreamReader; 084import org.junit.jupiter.api.AfterAll; 085import org.junit.jupiter.api.AfterEach; 086import org.junit.jupiter.api.BeforeAll; 087import org.junit.jupiter.api.BeforeEach; 088import org.junit.jupiter.api.Tag; 089import org.junit.jupiter.api.Test; 090import org.junit.jupiter.api.TestInfo; 091import org.mockito.Mockito; 092import org.slf4j.Logger; 093import org.slf4j.LoggerFactory; 094 095import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 096import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 097 098import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 099import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.MutationType; 100import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.BulkLoadDescriptor; 101import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.CompactionDescriptor; 102import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor; 103import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor.FlushAction; 104import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.FlushDescriptor.StoreFlushDescriptor; 105import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor; 106import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.RegionEventDescriptor.EventType; 107import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.StoreDescriptor; 108 109/** 110 * Tests of HRegion methods for replaying flush, compaction, region open, etc events for secondary 111 * region replicas 112 */ 113@SuppressWarnings("deprecation") 114@Tag(LargeTests.TAG) 115public class TestHRegionReplayEvents { 116 117 private static final Logger LOG = LoggerFactory.getLogger(TestHRegionReplayEvents.class); 118 private String name; 119 120 private static HBaseTestingUtil TEST_UTIL; 121 122 public static Configuration CONF; 123 private String dir; 124 125 private byte[][] families = 126 new byte[][] { Bytes.toBytes("cf1"), Bytes.toBytes("cf2"), Bytes.toBytes("cf3") }; 127 128 // Test names 129 protected byte[] tableName; 130 protected String method; 131 protected final byte[] row = Bytes.toBytes("rowA"); 132 protected final byte[] row2 = Bytes.toBytes("rowB"); 133 protected byte[] cq = Bytes.toBytes("cq"); 134 135 // per test fields 136 private Path rootDir; 137 private TableDescriptor htd; 138 private RegionServerServices rss; 139 private RegionInfo primaryHri, secondaryHri; 140 private HRegion primaryRegion, secondaryRegion; 141 private WAL walPrimary, walSecondary; 142 private WALStreamReader reader; 143 144 @BeforeAll 145 public static void setUpBeforeClass() throws Exception { 146 TEST_UTIL = new HBaseTestingUtil(); 147 TEST_UTIL.startMiniDFSCluster(1); 148 } 149 150 @AfterAll 151 public static void tearDownAfterClass() throws Exception { 152 LOG.info("Cleaning test directory: " + TEST_UTIL.getDataTestDir()); 153 TEST_UTIL.cleanupTestDir(); 154 TEST_UTIL.shutdownMiniDFSCluster(); 155 } 156 157 @BeforeEach 158 public void setUp(TestInfo testInfo) throws Exception { 159 this.name = testInfo.getTestMethod().get().getName(); 160 CONF = TEST_UTIL.getConfiguration(); 161 dir = TEST_UTIL.getDataTestDir("TestHRegionReplayEvents").toString(); 162 method = name; 163 tableName = Bytes.toBytes(name); 164 rootDir = new Path(dir + method); 165 TEST_UTIL.getConfiguration().set(HConstants.HBASE_DIR, rootDir.toString()); 166 method = name; 167 TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TableName.valueOf(method)); 168 for (byte[] family : families) { 169 builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)); 170 } 171 htd = builder.build(); 172 173 long time = EnvironmentEdgeManager.currentTime(); 174 ChunkCreator.initialize(MemStoreLAB.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null, 175 MemStoreLAB.INDEX_CHUNK_SIZE_PERCENTAGE_DEFAULT); 176 primaryHri = 177 RegionInfoBuilder.newBuilder(htd.getTableName()).setRegionId(time).setReplicaId(0).build(); 178 secondaryHri = 179 RegionInfoBuilder.newBuilder(htd.getTableName()).setRegionId(time).setReplicaId(1).build(); 180 181 WALFactory wals = TestHRegion.createWALFactory(CONF, rootDir); 182 walPrimary = wals.getWAL(primaryHri); 183 walSecondary = wals.getWAL(secondaryHri); 184 185 rss = mock(RegionServerServices.class); 186 when(rss.getServerName()).thenReturn(ServerName.valueOf("foo", 1, 1)); 187 when(rss.getConfiguration()).thenReturn(CONF); 188 when(rss.getRegionServerAccounting()).thenReturn(new RegionServerAccounting(CONF)); 189 String string = 190 org.apache.hadoop.hbase.executor.EventType.RS_COMPACTED_FILES_DISCHARGER.toString(); 191 ExecutorService es = new ExecutorService(string); 192 es.startExecutorService(es.new ExecutorConfig().setCorePoolSize(1) 193 .setExecutorType(ExecutorType.RS_COMPACTED_FILES_DISCHARGER)); 194 when(rss.getExecutorService()).thenReturn(es); 195 primaryRegion = HRegion.createHRegion(primaryHri, rootDir, CONF, htd, walPrimary); 196 primaryRegion.close(); 197 List<HRegion> regions = new ArrayList<>(); 198 regions.add(primaryRegion); 199 Mockito.doReturn(regions).when(rss).getRegions(); 200 201 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 202 secondaryRegion = HRegion.openHRegion(secondaryHri, htd, null, CONF, rss, null); 203 204 reader = null; 205 } 206 207 @AfterEach 208 public void tearDown() throws Exception { 209 if (reader != null) { 210 reader.close(); 211 } 212 213 if (primaryRegion != null) { 214 HBaseTestingUtil.closeRegionAndWAL(primaryRegion); 215 } 216 if (secondaryRegion != null) { 217 HBaseTestingUtil.closeRegionAndWAL(secondaryRegion); 218 } 219 220 EnvironmentEdgeManagerTestHelper.reset(); 221 } 222 223 String getName() { 224 return name; 225 } 226 227 // Some of the test cases are as follows: 228 // 1. replay flush start marker again 229 // 2. replay flush with smaller seqId than what is there in memstore snapshot 230 // 3. replay flush with larger seqId than what is there in memstore snapshot 231 // 4. replay flush commit without flush prepare. non droppable memstore 232 // 5. replay flush commit without flush prepare. droppable memstore 233 // 6. replay open region event 234 // 7. replay open region event after flush start 235 // 8. replay flush form an earlier seqId (test ignoring seqIds) 236 // 9. start flush does not prevent region from closing. 237 238 @Test 239 public void testRegionReplicaSecondaryCannotFlush() throws IOException { 240 // load some data and flush ensure that the secondary replica will not execute the flush 241 242 // load some data to secondary by replaying 243 putDataByReplay(secondaryRegion, 0, 1000, cq, families); 244 245 verifyData(secondaryRegion, 0, 1000, cq, families); 246 247 // flush region 248 FlushResultImpl flush = (FlushResultImpl) secondaryRegion.flush(true); 249 assertEquals(FlushResultImpl.Result.CANNOT_FLUSH, flush.result); 250 251 verifyData(secondaryRegion, 0, 1000, cq, families); 252 253 // close the region, and inspect that it has not flushed 254 Map<byte[], List<HStoreFile>> files = secondaryRegion.close(false); 255 // assert that there are no files (due to flush) 256 for (List<HStoreFile> f : files.values()) { 257 assertTrue(f.isEmpty()); 258 } 259 } 260 261 /** 262 * Tests a case where we replay only a flush start marker, then the region is closed. This region 263 * should not block indefinitely 264 */ 265 @Test 266 public void testOnlyReplayingFlushStartDoesNotHoldUpRegionClose() throws IOException { 267 // load some data to primary and flush 268 int start = 0; 269 LOG.info("-- Writing some data to primary from " + start + " to " + (start + 100)); 270 putData(primaryRegion, Durability.SYNC_WAL, start, 100, cq, families); 271 LOG.info("-- Flushing primary, creating 3 files for 3 stores"); 272 primaryRegion.flush(true); 273 274 // now replay the edits and the flush marker 275 reader = createWALReaderForPrimary(); 276 277 LOG.info("-- Replaying edits and flush events in secondary"); 278 while (true) { 279 WAL.Entry entry = reader.next(); 280 if (entry == null) { 281 break; 282 } 283 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 284 if (flushDesc != null) { 285 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 286 LOG.info("-- Replaying flush start in secondary"); 287 secondaryRegion.replayWALFlushStartMarker(flushDesc); 288 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 289 LOG.info("-- NOT Replaying flush commit in secondary"); 290 } 291 } else { 292 replayEdit(secondaryRegion, entry); 293 } 294 } 295 296 assertTrue(rss.getRegionServerAccounting().getGlobalMemStoreDataSize() > 0); 297 // now close the region which should not cause hold because of un-committed flush 298 secondaryRegion.close(); 299 300 // verify that the memstore size is back to what it was 301 assertEquals(0, rss.getRegionServerAccounting().getGlobalMemStoreDataSize()); 302 } 303 304 static int replayEdit(HRegion region, WAL.Entry entry) throws IOException { 305 if (WALEdit.isMetaEditFamily(entry.getEdit().getCells().get(0))) { 306 return 0; // handled elsewhere 307 } 308 Put put = new Put(CellUtil.cloneRow(entry.getEdit().getCells().get(0))); 309 for (Cell cell : entry.getEdit().getCells()) 310 put.add(cell); 311 put.setDurability(Durability.SKIP_WAL); 312 MutationReplay mutation = new MutationReplay(MutationType.PUT, put, 0, 0); 313 region.batchReplay(new MutationReplay[] { mutation }, entry.getKey().getSequenceId()); 314 return Integer.parseInt(Bytes.toString(put.getRow())); 315 } 316 317 private WALStreamReader createWALReaderForPrimary() throws FileNotFoundException, IOException { 318 return NoEOFWALStreamReader.create(TEST_UTIL.getTestFileSystem(), 319 AbstractFSWALProvider.getCurrentFileName(walPrimary), TEST_UTIL.getConfiguration()); 320 } 321 322 @Test 323 public void testBatchReplayWithMultipleNonces() throws IOException { 324 try { 325 MutationReplay[] mutations = new MutationReplay[100]; 326 for (int i = 0; i < 100; i++) { 327 Put put = new Put(Bytes.toBytes(i)); 328 put.setDurability(Durability.SYNC_WAL); 329 for (byte[] familly : this.families) { 330 put.addColumn(familly, this.cq, null); 331 long nonceNum = i / 10; 332 mutations[i] = new MutationReplay(MutationType.PUT, put, nonceNum, nonceNum); 333 } 334 } 335 primaryRegion.batchReplay(mutations, 20); 336 } catch (Exception e) { 337 String msg = "Error while replay of batch with multiple nonces. "; 338 LOG.error(msg, e); 339 fail(msg + e.getMessage()); 340 } 341 } 342 343 @Test 344 public void testReplayFlushesAndCompactions() throws IOException { 345 // initiate a secondary region with some data. 346 347 // load some data to primary and flush. 3 flushes and some more unflushed data 348 putDataWithFlushes(primaryRegion, 100, 300, 100); 349 350 // compaction from primary 351 LOG.info("-- Compacting primary, only 1 store"); 352 primaryRegion.compactStore(Bytes.toBytes("cf1"), NoLimitThroughputController.INSTANCE); 353 354 // now replay the edits and the flush marker 355 reader = createWALReaderForPrimary(); 356 357 LOG.info("-- Replaying edits and flush events in secondary"); 358 int lastReplayed = 0; 359 int expectedStoreFileCount = 0; 360 while (true) { 361 WAL.Entry entry = reader.next(); 362 if (entry == null) { 363 break; 364 } 365 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 366 CompactionDescriptor compactionDesc = 367 WALEdit.getCompaction(entry.getEdit().getCells().get(0)); 368 if (flushDesc != null) { 369 // first verify that everything is replayed and visible before flush event replay 370 verifyData(secondaryRegion, 0, lastReplayed, cq, families); 371 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 372 long storeMemstoreSize = store.getMemStoreSize().getHeapSize(); 373 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 374 MemStoreSize mss = store.getFlushableSize(); 375 long storeSize = store.getSize(); 376 long storeSizeUncompressed = store.getStoreSizeUncompressed(); 377 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 378 LOG.info("-- Replaying flush start in secondary"); 379 PrepareFlushResult result = secondaryRegion.replayWALFlushStartMarker(flushDesc); 380 assertNull(result.result); 381 assertEquals(result.flushOpSeqId, flushDesc.getFlushSequenceNumber()); 382 383 // assert that the store memstore is smaller now 384 long newStoreMemstoreSize = store.getMemStoreSize().getHeapSize(); 385 LOG.info("Memstore size reduced by:" 386 + Strings.humanReadableInt(newStoreMemstoreSize - storeMemstoreSize)); 387 assertTrue(storeMemstoreSize > newStoreMemstoreSize); 388 389 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 390 LOG.info("-- Replaying flush commit in secondary"); 391 secondaryRegion.replayWALFlushCommitMarker(flushDesc); 392 393 // assert that the flush files are picked 394 expectedStoreFileCount++; 395 for (HStore s : secondaryRegion.getStores()) { 396 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 397 } 398 MemStoreSize newMss = store.getFlushableSize(); 399 assertTrue(mss.getHeapSize() > newMss.getHeapSize()); 400 401 // assert that the region memstore is smaller now 402 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 403 assertTrue(regionMemstoreSize > newRegionMemstoreSize); 404 405 // assert that the store sizes are bigger 406 assertTrue(store.getSize() > storeSize); 407 assertTrue(store.getStoreSizeUncompressed() > storeSizeUncompressed); 408 assertEquals(store.getSize(), store.getStorefilesSize()); 409 } 410 // after replay verify that everything is still visible 411 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 412 } else if (compactionDesc != null) { 413 secondaryRegion.replayWALCompactionMarker(compactionDesc, true, false, Long.MAX_VALUE); 414 415 // assert that the compaction is applied 416 for (HStore store : secondaryRegion.getStores()) { 417 if (store.getColumnFamilyName().equals("cf1")) { 418 assertEquals(1, store.getStorefilesCount()); 419 } else { 420 assertEquals(expectedStoreFileCount, store.getStorefilesCount()); 421 } 422 } 423 } else { 424 lastReplayed = replayEdit(secondaryRegion, entry); 425 } 426 } 427 428 assertEquals(400 - 1, lastReplayed); 429 LOG.info("-- Verifying edits from secondary"); 430 verifyData(secondaryRegion, 0, 400, cq, families); 431 432 LOG.info("-- Verifying edits from primary. Ensuring that files are not deleted"); 433 verifyData(primaryRegion, 0, lastReplayed, cq, families); 434 for (HStore store : primaryRegion.getStores()) { 435 if (store.getColumnFamilyName().equals("cf1")) { 436 assertEquals(1, store.getStorefilesCount()); 437 } else { 438 assertEquals(expectedStoreFileCount, store.getStorefilesCount()); 439 } 440 } 441 } 442 443 /** 444 * Tests cases where we prepare a flush with some seqId and we receive other flush start markers 445 * equal to, greater or less than the previous flush start marker. 446 */ 447 @Test 448 public void testReplayFlushStartMarkers() throws IOException { 449 // load some data to primary and flush. 1 flush and some more unflushed data 450 putDataWithFlushes(primaryRegion, 100, 100, 100); 451 int numRows = 200; 452 453 // now replay the edits and the flush marker 454 reader = createWALReaderForPrimary(); 455 456 LOG.info("-- Replaying edits and flush events in secondary"); 457 458 FlushDescriptor startFlushDesc = null; 459 460 int lastReplayed = 0; 461 while (true) { 462 WAL.Entry entry = reader.next(); 463 if (entry == null) { 464 break; 465 } 466 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 467 if (flushDesc != null) { 468 // first verify that everything is replayed and visible before flush event replay 469 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 470 long storeMemstoreSize = store.getMemStoreSize().getHeapSize(); 471 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 472 MemStoreSize mss = store.getFlushableSize(); 473 474 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 475 startFlushDesc = flushDesc; 476 LOG.info("-- Replaying flush start in secondary"); 477 PrepareFlushResult result = secondaryRegion.replayWALFlushStartMarker(startFlushDesc); 478 assertNull(result.result); 479 assertEquals(result.flushOpSeqId, startFlushDesc.getFlushSequenceNumber()); 480 assertTrue(regionMemstoreSize > 0); 481 assertTrue(mss.getHeapSize() > 0); 482 483 // assert that the store memstore is smaller now 484 long newStoreMemstoreSize = store.getMemStoreSize().getHeapSize(); 485 LOG.info("Memstore size reduced by:" 486 + Strings.humanReadableInt(newStoreMemstoreSize - storeMemstoreSize)); 487 assertTrue(storeMemstoreSize > newStoreMemstoreSize); 488 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 489 490 } 491 // after replay verify that everything is still visible 492 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 493 } else { 494 lastReplayed = replayEdit(secondaryRegion, entry); 495 } 496 } 497 498 // at this point, there should be some data (rows 0-100) in memstore snapshot 499 // and some more data in memstores (rows 100-200) 500 501 verifyData(secondaryRegion, 0, numRows, cq, families); 502 503 // Test case 1: replay the same flush start marker again 504 LOG.info("-- Replaying same flush start in secondary again"); 505 PrepareFlushResult result = secondaryRegion.replayWALFlushStartMarker(startFlushDesc); 506 assertNull(result); // this should return null. Ignoring the flush start marker 507 // assert that we still have prepared flush with the previous setup. 508 assertNotNull(secondaryRegion.getPrepareFlushResult()); 509 assertEquals(secondaryRegion.getPrepareFlushResult().flushOpSeqId, 510 startFlushDesc.getFlushSequenceNumber()); 511 assertTrue(secondaryRegion.getMemStoreDataSize() > 0); // memstore is not empty 512 verifyData(secondaryRegion, 0, numRows, cq, families); 513 514 // Test case 2: replay a flush start marker with a smaller seqId 515 FlushDescriptor startFlushDescSmallerSeqId = 516 clone(startFlushDesc, startFlushDesc.getFlushSequenceNumber() - 50); 517 LOG.info("-- Replaying same flush start in secondary again " + startFlushDescSmallerSeqId); 518 result = secondaryRegion.replayWALFlushStartMarker(startFlushDescSmallerSeqId); 519 assertNull(result); // this should return null. Ignoring the flush start marker 520 // assert that we still have prepared flush with the previous setup. 521 assertNotNull(secondaryRegion.getPrepareFlushResult()); 522 assertEquals(secondaryRegion.getPrepareFlushResult().flushOpSeqId, 523 startFlushDesc.getFlushSequenceNumber()); 524 assertTrue(secondaryRegion.getMemStoreDataSize() > 0); // memstore is not empty 525 verifyData(secondaryRegion, 0, numRows, cq, families); 526 527 // Test case 3: replay a flush start marker with a larger seqId 528 FlushDescriptor startFlushDescLargerSeqId = 529 clone(startFlushDesc, startFlushDesc.getFlushSequenceNumber() + 50); 530 LOG.info("-- Replaying same flush start in secondary again " + startFlushDescLargerSeqId); 531 result = secondaryRegion.replayWALFlushStartMarker(startFlushDescLargerSeqId); 532 assertNull(result); // this should return null. Ignoring the flush start marker 533 // assert that we still have prepared flush with the previous setup. 534 assertNotNull(secondaryRegion.getPrepareFlushResult()); 535 assertEquals(secondaryRegion.getPrepareFlushResult().flushOpSeqId, 536 startFlushDesc.getFlushSequenceNumber()); 537 assertTrue(secondaryRegion.getMemStoreDataSize() > 0); // memstore is not empty 538 verifyData(secondaryRegion, 0, numRows, cq, families); 539 540 LOG.info("-- Verifying edits from secondary"); 541 verifyData(secondaryRegion, 0, numRows, cq, families); 542 543 LOG.info("-- Verifying edits from primary."); 544 verifyData(primaryRegion, 0, numRows, cq, families); 545 } 546 547 /** 548 * Tests the case where we prepare a flush with some seqId and we receive a flush commit marker 549 * less than the previous flush start marker. 550 */ 551 @Test 552 public void testReplayFlushCommitMarkerSmallerThanFlushStartMarker() throws IOException { 553 // load some data to primary and flush. 2 flushes and some more unflushed data 554 putDataWithFlushes(primaryRegion, 100, 200, 100); 555 int numRows = 300; 556 557 // now replay the edits and the flush marker 558 reader = createWALReaderForPrimary(); 559 560 LOG.info("-- Replaying edits and flush events in secondary"); 561 FlushDescriptor startFlushDesc = null; 562 FlushDescriptor commitFlushDesc = null; 563 564 int lastReplayed = 0; 565 while (true) { 566 System.out.println(lastReplayed); 567 WAL.Entry entry = reader.next(); 568 if (entry == null) { 569 break; 570 } 571 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 572 if (flushDesc != null) { 573 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 574 // don't replay the first flush start marker, hold on to it, replay the second one 575 if (startFlushDesc == null) { 576 startFlushDesc = flushDesc; 577 } else { 578 LOG.info("-- Replaying flush start in secondary"); 579 startFlushDesc = flushDesc; 580 PrepareFlushResult result = secondaryRegion.replayWALFlushStartMarker(startFlushDesc); 581 assertNull(result.result); 582 } 583 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 584 // do not replay any flush commit yet 585 if (commitFlushDesc == null) { 586 commitFlushDesc = flushDesc; // hold on to the first flush commit marker 587 } 588 } 589 // after replay verify that everything is still visible 590 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 591 } else { 592 lastReplayed = replayEdit(secondaryRegion, entry); 593 } 594 } 595 596 // at this point, there should be some data (rows 0-200) in memstore snapshot 597 // and some more data in memstores (rows 200-300) 598 verifyData(secondaryRegion, 0, numRows, cq, families); 599 600 // no store files in the region 601 int expectedStoreFileCount = 0; 602 for (HStore s : secondaryRegion.getStores()) { 603 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 604 } 605 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 606 607 // Test case 1: replay the a flush commit marker smaller than what we have prepared 608 LOG.info("Testing replaying flush COMMIT " + commitFlushDesc + " on top of flush START" 609 + startFlushDesc); 610 assertTrue(commitFlushDesc.getFlushSequenceNumber() < startFlushDesc.getFlushSequenceNumber()); 611 612 LOG.info("-- Replaying flush commit in secondary" + commitFlushDesc); 613 secondaryRegion.replayWALFlushCommitMarker(commitFlushDesc); 614 615 // assert that the flush files are picked 616 expectedStoreFileCount++; 617 for (HStore s : secondaryRegion.getStores()) { 618 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 619 } 620 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 621 MemStoreSize mss = store.getFlushableSize(); 622 assertTrue(mss.getHeapSize() > 0); // assert that the memstore is not dropped 623 624 // assert that the region memstore is same as before 625 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 626 assertEquals(regionMemstoreSize, newRegionMemstoreSize); 627 628 assertNotNull(secondaryRegion.getPrepareFlushResult()); // not dropped 629 630 LOG.info("-- Verifying edits from secondary"); 631 verifyData(secondaryRegion, 0, numRows, cq, families); 632 633 LOG.info("-- Verifying edits from primary."); 634 verifyData(primaryRegion, 0, numRows, cq, families); 635 } 636 637 /** 638 * Tests the case where we prepare a flush with some seqId and we receive a flush commit marker 639 * larger than the previous flush start marker. 640 */ 641 @Test 642 public void testReplayFlushCommitMarkerLargerThanFlushStartMarker() throws IOException { 643 // load some data to primary and flush. 1 flush and some more unflushed data 644 putDataWithFlushes(primaryRegion, 100, 100, 100); 645 int numRows = 200; 646 647 // now replay the edits and the flush marker 648 reader = createWALReaderForPrimary(); 649 650 LOG.info("-- Replaying edits and flush events in secondary"); 651 FlushDescriptor startFlushDesc = null; 652 FlushDescriptor commitFlushDesc = null; 653 654 int lastReplayed = 0; 655 while (true) { 656 WAL.Entry entry = reader.next(); 657 if (entry == null) { 658 break; 659 } 660 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 661 if (flushDesc != null) { 662 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 663 if (startFlushDesc == null) { 664 LOG.info("-- Replaying flush start in secondary"); 665 startFlushDesc = flushDesc; 666 PrepareFlushResult result = secondaryRegion.replayWALFlushStartMarker(startFlushDesc); 667 assertNull(result.result); 668 } 669 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 670 // do not replay any flush commit yet 671 // hold on to the flush commit marker but simulate a larger 672 // flush commit seqId 673 commitFlushDesc = FlushDescriptor.newBuilder(flushDesc) 674 .setFlushSequenceNumber(flushDesc.getFlushSequenceNumber() + 50).build(); 675 } 676 // after replay verify that everything is still visible 677 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 678 } else { 679 lastReplayed = replayEdit(secondaryRegion, entry); 680 } 681 } 682 683 // at this point, there should be some data (rows 0-100) in memstore snapshot 684 // and some more data in memstores (rows 100-200) 685 verifyData(secondaryRegion, 0, numRows, cq, families); 686 687 // no store files in the region 688 int expectedStoreFileCount = 0; 689 for (HStore s : secondaryRegion.getStores()) { 690 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 691 } 692 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 693 694 // Test case 1: replay the a flush commit marker larger than what we have prepared 695 LOG.info("Testing replaying flush COMMIT " + commitFlushDesc + " on top of flush START" 696 + startFlushDesc); 697 assertTrue(commitFlushDesc.getFlushSequenceNumber() > startFlushDesc.getFlushSequenceNumber()); 698 699 LOG.info("-- Replaying flush commit in secondary" + commitFlushDesc); 700 secondaryRegion.replayWALFlushCommitMarker(commitFlushDesc); 701 702 // assert that the flush files are picked 703 expectedStoreFileCount++; 704 for (HStore s : secondaryRegion.getStores()) { 705 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 706 } 707 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 708 MemStoreSize mss = store.getFlushableSize(); 709 assertTrue(mss.getHeapSize() > 0); // assert that the memstore is not dropped 710 711 // assert that the region memstore is smaller than before, but not empty 712 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 713 assertTrue(newRegionMemstoreSize > 0); 714 assertTrue(regionMemstoreSize > newRegionMemstoreSize); 715 716 assertNull(secondaryRegion.getPrepareFlushResult()); // prepare snapshot should be dropped 717 718 LOG.info("-- Verifying edits from secondary"); 719 verifyData(secondaryRegion, 0, numRows, cq, families); 720 721 LOG.info("-- Verifying edits from primary."); 722 verifyData(primaryRegion, 0, numRows, cq, families); 723 } 724 725 /** 726 * Tests the case where we receive a flush commit before receiving any flush prepare markers. The 727 * memstore edits should be dropped after the flush commit replay since they should be in flushed 728 * files 729 */ 730 @Test 731 public void testReplayFlushCommitMarkerWithoutFlushStartMarkerDroppableMemstore() 732 throws IOException { 733 testReplayFlushCommitMarkerWithoutFlushStartMarker(true); 734 } 735 736 /** 737 * Tests the case where we receive a flush commit before receiving any flush prepare markers. The 738 * memstore edits should be not dropped after the flush commit replay since not every edit will be 739 * in flushed files (based on seqId) 740 */ 741 @Test 742 public void testReplayFlushCommitMarkerWithoutFlushStartMarkerNonDroppableMemstore() 743 throws IOException { 744 testReplayFlushCommitMarkerWithoutFlushStartMarker(false); 745 } 746 747 /** 748 * Tests the case where we receive a flush commit before receiving any flush prepare markers 749 */ 750 public void testReplayFlushCommitMarkerWithoutFlushStartMarker(boolean droppableMemstore) 751 throws IOException { 752 // load some data to primary and flush. 1 flushes and some more unflushed data. 753 // write more data after flush depending on whether droppableSnapshot 754 putDataWithFlushes(primaryRegion, 100, 100, droppableMemstore ? 0 : 100); 755 int numRows = droppableMemstore ? 100 : 200; 756 757 // now replay the edits and the flush marker 758 reader = createWALReaderForPrimary(); 759 760 LOG.info("-- Replaying edits and flush events in secondary"); 761 FlushDescriptor commitFlushDesc = null; 762 763 int lastReplayed = 0; 764 while (true) { 765 WAL.Entry entry = reader.next(); 766 if (entry == null) { 767 break; 768 } 769 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 770 if (flushDesc != null) { 771 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 772 // do not replay flush start marker 773 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 774 commitFlushDesc = flushDesc; // hold on to the flush commit marker 775 } 776 // after replay verify that everything is still visible 777 verifyData(secondaryRegion, 0, lastReplayed + 1, cq, families); 778 } else { 779 lastReplayed = replayEdit(secondaryRegion, entry); 780 } 781 } 782 783 // at this point, there should be some data (rows 0-200) in the memstore without snapshot 784 // and some more data in memstores (rows 100-300) 785 verifyData(secondaryRegion, 0, numRows, cq, families); 786 787 // no store files in the region 788 int expectedStoreFileCount = 0; 789 for (HStore s : secondaryRegion.getStores()) { 790 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 791 } 792 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 793 794 // Test case 1: replay a flush commit marker without start flush marker 795 assertNull(secondaryRegion.getPrepareFlushResult()); 796 assertTrue(commitFlushDesc.getFlushSequenceNumber() > 0); 797 798 // ensure all files are visible in secondary 799 for (HStore store : secondaryRegion.getStores()) { 800 assertTrue(store.getMaxSequenceId().orElse(0L) <= secondaryRegion.getReadPoint(null)); 801 } 802 803 LOG.info("-- Replaying flush commit in secondary" + commitFlushDesc); 804 secondaryRegion.replayWALFlushCommitMarker(commitFlushDesc); 805 806 // assert that the flush files are picked 807 expectedStoreFileCount++; 808 for (HStore s : secondaryRegion.getStores()) { 809 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 810 } 811 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 812 MemStoreSize mss = store.getFlushableSize(); 813 if (droppableMemstore) { 814 // assert that the memstore is dropped 815 assertTrue(mss.getHeapSize() == MutableSegment.DEEP_OVERHEAD); 816 } else { 817 assertTrue(mss.getHeapSize() > 0); // assert that the memstore is not dropped 818 } 819 820 // assert that the region memstore is same as before (we could not drop) 821 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 822 if (droppableMemstore) { 823 assertTrue(0 == newRegionMemstoreSize); 824 } else { 825 assertTrue(regionMemstoreSize == newRegionMemstoreSize); 826 } 827 828 LOG.info("-- Verifying edits from secondary"); 829 verifyData(secondaryRegion, 0, numRows, cq, families); 830 831 LOG.info("-- Verifying edits from primary."); 832 verifyData(primaryRegion, 0, numRows, cq, families); 833 } 834 835 private FlushDescriptor clone(FlushDescriptor flush, long flushSeqId) { 836 return FlushDescriptor.newBuilder(flush).setFlushSequenceNumber(flushSeqId).build(); 837 } 838 839 /** 840 * Tests replaying region open markers from primary region. Checks whether the files are picked up 841 */ 842 @Test 843 public void testReplayRegionOpenEvent() throws IOException { 844 putDataWithFlushes(primaryRegion, 100, 0, 100); // no flush 845 int numRows = 100; 846 847 // close the region and open again. 848 primaryRegion.close(); 849 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 850 851 // now replay the edits and the flush marker 852 reader = createWALReaderForPrimary(); 853 List<RegionEventDescriptor> regionEvents = Lists.newArrayList(); 854 855 LOG.info("-- Replaying edits and region events in secondary"); 856 while (true) { 857 WAL.Entry entry = reader.next(); 858 if (entry == null) { 859 break; 860 } 861 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 862 RegionEventDescriptor regionEventDesc = 863 WALEdit.getRegionEventDescriptor(entry.getEdit().getCells().get(0)); 864 865 if (flushDesc != null) { 866 // don't replay flush events 867 } else if (regionEventDesc != null) { 868 regionEvents.add(regionEventDesc); 869 } else { 870 // don't replay edits 871 } 872 } 873 874 // we should have 1 open, 1 close and 1 open event 875 assertEquals(3, regionEvents.size()); 876 877 // replay the first region open event. 878 secondaryRegion.replayWALRegionEventMarker(regionEvents.get(0)); 879 880 // replay the close event as well 881 secondaryRegion.replayWALRegionEventMarker(regionEvents.get(1)); 882 883 // no store files in the region 884 int expectedStoreFileCount = 0; 885 for (HStore s : secondaryRegion.getStores()) { 886 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 887 } 888 long regionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 889 assertTrue(regionMemstoreSize == 0); 890 891 // now replay the region open event that should contain new file locations 892 LOG.info("Testing replaying region open event " + regionEvents.get(2)); 893 secondaryRegion.replayWALRegionEventMarker(regionEvents.get(2)); 894 895 // assert that the flush files are picked 896 expectedStoreFileCount++; 897 for (HStore s : secondaryRegion.getStores()) { 898 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 899 } 900 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 901 MemStoreSize mss = store.getFlushableSize(); 902 assertTrue(mss.getHeapSize() == MutableSegment.DEEP_OVERHEAD); 903 904 // assert that the region memstore is empty 905 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 906 assertTrue(newRegionMemstoreSize == 0); 907 908 assertNull(secondaryRegion.getPrepareFlushResult()); // prepare snapshot should be dropped if 909 // any 910 911 LOG.info("-- Verifying edits from secondary"); 912 verifyData(secondaryRegion, 0, numRows, cq, families); 913 914 LOG.info("-- Verifying edits from primary."); 915 verifyData(primaryRegion, 0, numRows, cq, families); 916 } 917 918 /** 919 * Tests the case where we replay a region open event after a flush start but before receiving 920 * flush commit 921 */ 922 @Test 923 public void testReplayRegionOpenEventAfterFlushStart() throws IOException { 924 putDataWithFlushes(primaryRegion, 100, 100, 100); 925 int numRows = 200; 926 927 // close the region and open again. 928 primaryRegion.close(); 929 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 930 931 // now replay the edits and the flush marker 932 reader = createWALReaderForPrimary(); 933 List<RegionEventDescriptor> regionEvents = Lists.newArrayList(); 934 935 LOG.info("-- Replaying edits and region events in secondary"); 936 while (true) { 937 WAL.Entry entry = reader.next(); 938 if (entry == null) { 939 break; 940 } 941 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 942 RegionEventDescriptor regionEventDesc = 943 WALEdit.getRegionEventDescriptor(entry.getEdit().getCells().get(0)); 944 945 if (flushDesc != null) { 946 // only replay flush start 947 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 948 secondaryRegion.replayWALFlushStartMarker(flushDesc); 949 } 950 } else if (regionEventDesc != null) { 951 regionEvents.add(regionEventDesc); 952 } else { 953 replayEdit(secondaryRegion, entry); 954 } 955 } 956 957 // at this point, there should be some data (rows 0-100) in the memstore snapshot 958 // and some more data in memstores (rows 100-200) 959 verifyData(secondaryRegion, 0, numRows, cq, families); 960 961 // we should have 1 open, 1 close and 1 open event 962 assertEquals(3, regionEvents.size()); 963 964 // no store files in the region 965 int expectedStoreFileCount = 0; 966 for (HStore s : secondaryRegion.getStores()) { 967 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 968 } 969 970 // now replay the region open event that should contain new file locations 971 LOG.info("Testing replaying region open event " + regionEvents.get(2)); 972 secondaryRegion.replayWALRegionEventMarker(regionEvents.get(2)); 973 974 // assert that the flush files are picked 975 expectedStoreFileCount = 2; // two flushes happened 976 for (HStore s : secondaryRegion.getStores()) { 977 assertEquals(expectedStoreFileCount, s.getStorefilesCount()); 978 } 979 HStore store = secondaryRegion.getStore(Bytes.toBytes("cf1")); 980 MemStoreSize newSnapshotSize = store.getSnapshotSize(); 981 assertTrue(newSnapshotSize.getDataSize() == 0); 982 983 // assert that the region memstore is empty 984 long newRegionMemstoreSize = secondaryRegion.getMemStoreDataSize(); 985 assertTrue(newRegionMemstoreSize == 0); 986 987 assertNull(secondaryRegion.getPrepareFlushResult()); // prepare snapshot should be dropped if 988 // any 989 990 LOG.info("-- Verifying edits from secondary"); 991 verifyData(secondaryRegion, 0, numRows, cq, families); 992 993 LOG.info("-- Verifying edits from primary."); 994 verifyData(primaryRegion, 0, numRows, cq, families); 995 } 996 997 /** 998 * Tests whether edits coming in for replay are skipped which have smaller seq id than the seqId 999 * of the last replayed region open event. 1000 */ 1001 @Test 1002 public void testSkippingEditsWithSmallerSeqIdAfterRegionOpenEvent() throws IOException { 1003 putDataWithFlushes(primaryRegion, 100, 100, 0); 1004 int numRows = 100; 1005 1006 // close the region and open again. 1007 primaryRegion.close(); 1008 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 1009 1010 // now replay the edits and the flush marker 1011 reader = createWALReaderForPrimary(); 1012 List<RegionEventDescriptor> regionEvents = Lists.newArrayList(); 1013 List<WAL.Entry> edits = Lists.newArrayList(); 1014 1015 LOG.info("-- Replaying edits and region events in secondary"); 1016 while (true) { 1017 WAL.Entry entry = reader.next(); 1018 if (entry == null) { 1019 break; 1020 } 1021 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1022 RegionEventDescriptor regionEventDesc = 1023 WALEdit.getRegionEventDescriptor(entry.getEdit().getCells().get(0)); 1024 1025 if (flushDesc != null) { 1026 // don't replay flushes 1027 } else if (regionEventDesc != null) { 1028 regionEvents.add(regionEventDesc); 1029 } else { 1030 edits.add(entry); 1031 } 1032 } 1033 1034 // replay the region open of first open, but with the seqid of the second open 1035 // this way non of the flush files will be picked up. 1036 secondaryRegion.replayWALRegionEventMarker(RegionEventDescriptor.newBuilder(regionEvents.get(0)) 1037 .setLogSequenceNumber(regionEvents.get(2).getLogSequenceNumber()).build()); 1038 1039 // replay edits from the before region close. If replay does not 1040 // skip these the following verification will NOT fail. 1041 for (WAL.Entry entry : edits) { 1042 replayEdit(secondaryRegion, entry); 1043 } 1044 1045 boolean expectedFail = false; 1046 try { 1047 verifyData(secondaryRegion, 0, numRows, cq, families); 1048 } catch (AssertionError e) { 1049 expectedFail = true; // expected 1050 } 1051 if (!expectedFail) { 1052 fail("Should have failed this verification"); 1053 } 1054 } 1055 1056 @Test 1057 public void testReplayFlushSeqIds() throws IOException { 1058 // load some data to primary and flush 1059 int start = 0; 1060 LOG.info("-- Writing some data to primary from " + start + " to " + (start + 100)); 1061 putData(primaryRegion, Durability.SYNC_WAL, start, 100, cq, families); 1062 LOG.info("-- Flushing primary, creating 3 files for 3 stores"); 1063 primaryRegion.flush(true); 1064 1065 // now replay the flush marker 1066 reader = createWALReaderForPrimary(); 1067 1068 long flushSeqId = -1; 1069 LOG.info("-- Replaying flush events in secondary"); 1070 while (true) { 1071 WAL.Entry entry = reader.next(); 1072 if (entry == null) { 1073 break; 1074 } 1075 FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1076 if (flushDesc != null) { 1077 if (flushDesc.getAction() == FlushAction.START_FLUSH) { 1078 LOG.info("-- Replaying flush start in secondary"); 1079 secondaryRegion.replayWALFlushStartMarker(flushDesc); 1080 flushSeqId = flushDesc.getFlushSequenceNumber(); 1081 } else if (flushDesc.getAction() == FlushAction.COMMIT_FLUSH) { 1082 LOG.info("-- Replaying flush commit in secondary"); 1083 secondaryRegion.replayWALFlushCommitMarker(flushDesc); 1084 assertEquals(flushSeqId, flushDesc.getFlushSequenceNumber()); 1085 } 1086 } 1087 // else do not replay 1088 } 1089 1090 // TODO: what to do with this? 1091 // assert that the newly picked up flush file is visible 1092 long readPoint = secondaryRegion.getMVCC().getReadPoint(); 1093 assertEquals(flushSeqId, readPoint); 1094 1095 // after replay verify that everything is still visible 1096 verifyData(secondaryRegion, 0, 100, cq, families); 1097 } 1098 1099 @Test 1100 public void testSeqIdsFromReplay() throws IOException { 1101 // test the case where seqId's coming from replayed WALEdits are made persisted with their 1102 // original seqIds and they are made visible through mvcc read point upon replay 1103 String method = name; 1104 byte[] tableName = Bytes.toBytes(method); 1105 byte[] family = Bytes.toBytes("family"); 1106 1107 HRegion region = initHRegion(tableName, family); 1108 try { 1109 // replay an entry that is bigger than current read point 1110 long readPoint = region.getMVCC().getReadPoint(); 1111 long origSeqId = readPoint + 100; 1112 1113 Put put = new Put(row).addColumn(family, row, row); 1114 put.setDurability(Durability.SKIP_WAL); // we replay with skip wal 1115 replay(region, put, origSeqId); 1116 1117 // read point should have advanced to this seqId 1118 assertGet(region, family, row); 1119 1120 // region seqId should have advanced at least to this seqId 1121 assertEquals(origSeqId, region.getReadPoint(null)); 1122 1123 // replay an entry that is smaller than current read point 1124 // caution: adding an entry below current read point might cause partial dirty reads. Normal 1125 // replay does not allow reads while replay is going on. 1126 put = new Put(row2).addColumn(family, row2, row2); 1127 put.setDurability(Durability.SKIP_WAL); 1128 replay(region, put, origSeqId - 50); 1129 1130 assertGet(region, family, row2); 1131 } finally { 1132 region.close(); 1133 } 1134 } 1135 1136 /** 1137 * Tests that a region opened in secondary mode would not write region open / close events to its 1138 * WAL. 1139 */ 1140 @Test 1141 public void testSecondaryRegionDoesNotWriteRegionEventsToWAL() throws IOException { 1142 secondaryRegion.close(); 1143 walSecondary = spy(walSecondary); 1144 1145 // test for region open and close 1146 secondaryRegion = HRegion.openHRegion(secondaryHri, htd, walSecondary, CONF, rss, null); 1147 verify(walSecondary, times(0)).appendData(any(RegionInfo.class), any(WALKeyImpl.class), 1148 any(WALEdit.class)); 1149 1150 // test for replay prepare flush 1151 putDataByReplay(secondaryRegion, 0, 10, cq, families); 1152 secondaryRegion.replayWALFlushStartMarker(FlushDescriptor.newBuilder() 1153 .setFlushSequenceNumber(10) 1154 .setTableName(UnsafeByteOperations 1155 .unsafeWrap(primaryRegion.getTableDescriptor().getTableName().getName())) 1156 .setAction(FlushAction.START_FLUSH) 1157 .setEncodedRegionName( 1158 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getEncodedNameAsBytes())) 1159 .setRegionName(UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getRegionName())) 1160 .build()); 1161 1162 verify(walSecondary, times(0)).appendData(any(RegionInfo.class), any(WALKeyImpl.class), 1163 any(WALEdit.class)); 1164 1165 secondaryRegion.close(); 1166 verify(walSecondary, times(0)).appendData(any(RegionInfo.class), any(WALKeyImpl.class), 1167 any(WALEdit.class)); 1168 } 1169 1170 /** 1171 * Tests the reads enabled flag for the region. When unset all reads should be rejected 1172 */ 1173 @Test 1174 public void testRegionReadsEnabledFlag() throws IOException { 1175 1176 putDataByReplay(secondaryRegion, 0, 100, cq, families); 1177 1178 verifyData(secondaryRegion, 0, 100, cq, families); 1179 1180 // now disable reads 1181 secondaryRegion.setReadsEnabled(false); 1182 try { 1183 verifyData(secondaryRegion, 0, 100, cq, families); 1184 fail("Should have failed with IOException"); 1185 } catch (IOException ex) { 1186 // expected 1187 } 1188 1189 // verify that we can still replay data 1190 putDataByReplay(secondaryRegion, 100, 100, cq, families); 1191 1192 // now enable reads again 1193 secondaryRegion.setReadsEnabled(true); 1194 verifyData(secondaryRegion, 0, 200, cq, families); 1195 } 1196 1197 /** 1198 * Tests the case where a request for flush cache is sent to the region, but region cannot flush. 1199 * It should write the flush request marker instead. 1200 */ 1201 @Test 1202 public void testWriteFlushRequestMarker() throws IOException { 1203 // primary region is empty at this point. Request a flush with writeFlushRequestWalMarker=false 1204 FlushResultImpl result = primaryRegion.flushcache(true, false, FlushLifeCycleTracker.DUMMY); 1205 assertNotNull(result); 1206 assertEquals(FlushResultImpl.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, result.result); 1207 assertFalse(result.wroteFlushWalMarker); 1208 1209 // request flush again, but this time with writeFlushRequestWalMarker = true 1210 result = primaryRegion.flushcache(true, true, FlushLifeCycleTracker.DUMMY); 1211 assertNotNull(result); 1212 assertEquals(FlushResultImpl.Result.CANNOT_FLUSH_MEMSTORE_EMPTY, result.result); 1213 assertTrue(result.wroteFlushWalMarker); 1214 1215 List<FlushDescriptor> flushes = Lists.newArrayList(); 1216 reader = createWALReaderForPrimary(); 1217 while (true) { 1218 WAL.Entry entry = reader.next(); 1219 if (entry == null) { 1220 break; 1221 } 1222 FlushDescriptor flush = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1223 if (flush != null) { 1224 flushes.add(flush); 1225 } 1226 } 1227 1228 assertEquals(1, flushes.size()); 1229 assertNotNull(flushes.get(0)); 1230 assertEquals(FlushDescriptor.FlushAction.CANNOT_FLUSH, flushes.get(0).getAction()); 1231 } 1232 1233 /** 1234 * Test the case where the secondary region replica is not in reads enabled state because it is 1235 * waiting for a flush or region open marker from primary region. Replaying CANNOT_FLUSH flush 1236 * marker entry should restore the reads enabled status in the region and allow the reads to 1237 * continue. 1238 */ 1239 @Test 1240 public void testReplayingFlushRequestRestoresReadsEnabledState() throws IOException { 1241 disableReads(secondaryRegion); 1242 1243 // Test case 1: Test that replaying CANNOT_FLUSH request marker assuming this came from 1244 // triggered flush restores readsEnabled 1245 primaryRegion.flushcache(true, true, FlushLifeCycleTracker.DUMMY); 1246 reader = createWALReaderForPrimary(); 1247 while (true) { 1248 WAL.Entry entry = reader.next(); 1249 if (entry == null) { 1250 break; 1251 } 1252 FlushDescriptor flush = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1253 if (flush != null) { 1254 secondaryRegion.replayWALFlushMarker(flush, entry.getKey().getSequenceId()); 1255 } 1256 } 1257 1258 // now reads should be enabled 1259 secondaryRegion.get(new Get(Bytes.toBytes(0))); 1260 } 1261 1262 /** 1263 * Test the case where the secondary region replica is not in reads enabled state because it is 1264 * waiting for a flush or region open marker from primary region. Replaying flush start and commit 1265 * entries should restore the reads enabled status in the region and allow the reads to continue. 1266 */ 1267 @Test 1268 public void testReplayingFlushRestoresReadsEnabledState() throws IOException { 1269 // Test case 2: Test that replaying FLUSH_START and FLUSH_COMMIT markers assuming these came 1270 // from triggered flush restores readsEnabled 1271 disableReads(secondaryRegion); 1272 1273 // put some data in primary 1274 putData(primaryRegion, Durability.SYNC_WAL, 0, 100, cq, families); 1275 primaryRegion.flush(true); 1276 // I seem to need to push more edits through so the WAL flushes on local fs. This was not 1277 // needed before HBASE-15028. Not sure whats up. I can see that we have not flushed if I 1278 // look at the WAL if I pause the test here and then use WALPrettyPrinter to look at content.. 1279 // Doing same check before HBASE-15028 I can see all edits flushed to the WAL. Somethings up 1280 // but can't figure it... and this is only test that seems to suffer this flush issue. 1281 // St.Ack 20160201 1282 putData(primaryRegion, Durability.SYNC_WAL, 0, 100, cq, families); 1283 1284 reader = createWALReaderForPrimary(); 1285 while (true) { 1286 WAL.Entry entry = reader.next(); 1287 LOG.info(Objects.toString(entry)); 1288 if (entry == null) { 1289 break; 1290 } 1291 FlushDescriptor flush = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1292 if (flush != null) { 1293 secondaryRegion.replayWALFlushMarker(flush, entry.getKey().getSequenceId()); 1294 } else { 1295 replayEdit(secondaryRegion, entry); 1296 } 1297 } 1298 1299 // now reads should be enabled 1300 verifyData(secondaryRegion, 0, 100, cq, families); 1301 } 1302 1303 /** 1304 * Test the case where the secondary region replica is not in reads enabled state because it is 1305 * waiting for a flush or region open marker from primary region. Replaying flush start and commit 1306 * entries should restore the reads enabled status in the region and allow the reads to continue. 1307 */ 1308 @Test 1309 public void testReplayingFlushWithEmptyMemstoreRestoresReadsEnabledState() throws IOException { 1310 // Test case 2: Test that replaying FLUSH_START and FLUSH_COMMIT markers assuming these came 1311 // from triggered flush restores readsEnabled 1312 disableReads(secondaryRegion); 1313 1314 // put some data in primary 1315 putData(primaryRegion, Durability.SYNC_WAL, 0, 100, cq, families); 1316 primaryRegion.flush(true); 1317 1318 reader = createWALReaderForPrimary(); 1319 while (true) { 1320 WAL.Entry entry = reader.next(); 1321 if (entry == null) { 1322 break; 1323 } 1324 FlushDescriptor flush = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1325 if (flush != null) { 1326 secondaryRegion.replayWALFlushMarker(flush, entry.getKey().getSequenceId()); 1327 } 1328 } 1329 1330 // now reads should be enabled 1331 verifyData(secondaryRegion, 0, 100, cq, families); 1332 } 1333 1334 /** 1335 * Test the case where the secondary region replica is not in reads enabled state because it is 1336 * waiting for a flush or region open marker from primary region. Replaying region open event 1337 * entry from primary should restore the reads enabled status in the region and allow the reads to 1338 * continue. 1339 */ 1340 @Test 1341 public void testReplayingRegionOpenEventRestoresReadsEnabledState() throws IOException { 1342 // Test case 3: Test that replaying region open event markers restores readsEnabled 1343 disableReads(secondaryRegion); 1344 1345 primaryRegion.close(); 1346 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 1347 1348 reader = createWALReaderForPrimary(); 1349 while (true) { 1350 WAL.Entry entry = reader.next(); 1351 if (entry == null) { 1352 break; 1353 } 1354 1355 RegionEventDescriptor regionEventDesc = 1356 WALEdit.getRegionEventDescriptor(entry.getEdit().getCells().get(0)); 1357 1358 if (regionEventDesc != null) { 1359 secondaryRegion.replayWALRegionEventMarker(regionEventDesc); 1360 } 1361 } 1362 1363 // now reads should be enabled 1364 secondaryRegion.get(new Get(Bytes.toBytes(0))); 1365 } 1366 1367 @Test 1368 public void testRefresStoreFiles() throws IOException { 1369 assertEquals(0, primaryRegion.getStoreFileList(families).size()); 1370 assertEquals(0, secondaryRegion.getStoreFileList(families).size()); 1371 1372 // Test case 1: refresh with an empty region 1373 secondaryRegion.refreshStoreFiles(); 1374 assertEquals(0, secondaryRegion.getStoreFileList(families).size()); 1375 1376 // do one flush 1377 putDataWithFlushes(primaryRegion, 100, 100, 0); 1378 int numRows = 100; 1379 1380 // refresh the store file list, and ensure that the files are picked up. 1381 secondaryRegion.refreshStoreFiles(); 1382 assertPathListsEqual(primaryRegion.getStoreFileList(families), 1383 secondaryRegion.getStoreFileList(families)); 1384 assertEquals(families.length, secondaryRegion.getStoreFileList(families).size()); 1385 1386 LOG.info("-- Verifying edits from secondary"); 1387 verifyData(secondaryRegion, 0, numRows, cq, families); 1388 1389 // Test case 2: 3 some more flushes 1390 putDataWithFlushes(primaryRegion, 100, 300, 0); 1391 numRows = 300; 1392 1393 // refresh the store file list, and ensure that the files are picked up. 1394 secondaryRegion.refreshStoreFiles(); 1395 assertPathListsEqual(primaryRegion.getStoreFileList(families), 1396 secondaryRegion.getStoreFileList(families)); 1397 assertEquals(families.length * 4, secondaryRegion.getStoreFileList(families).size()); 1398 1399 LOG.info("-- Verifying edits from secondary"); 1400 verifyData(secondaryRegion, 0, numRows, cq, families); 1401 1402 if (FSUtils.WINDOWS) { 1403 // compaction cannot move files while they are open in secondary on windows. Skip remaining. 1404 return; 1405 } 1406 1407 // Test case 3: compact primary files 1408 primaryRegion.compactStores(); 1409 List<HRegion> regions = new ArrayList<>(); 1410 regions.add(primaryRegion); 1411 Mockito.doReturn(regions).when(rss).getRegions(); 1412 CompactedHFilesDischarger cleaner = new CompactedHFilesDischarger(100, null, rss, false); 1413 cleaner.chore(); 1414 secondaryRegion.refreshStoreFiles(); 1415 assertPathListsEqual(primaryRegion.getStoreFileList(families), 1416 secondaryRegion.getStoreFileList(families)); 1417 assertEquals(families.length, secondaryRegion.getStoreFileList(families).size()); 1418 1419 LOG.info("-- Verifying edits from secondary"); 1420 verifyData(secondaryRegion, 0, numRows, cq, families); 1421 1422 LOG.info("-- Replaying edits in secondary"); 1423 1424 // Test case 4: replay some edits, ensure that memstore is dropped. 1425 assertTrue(secondaryRegion.getMemStoreDataSize() == 0); 1426 putDataWithFlushes(primaryRegion, 400, 400, 0); 1427 numRows = 400; 1428 1429 reader = createWALReaderForPrimary(); 1430 while (true) { 1431 WAL.Entry entry = reader.next(); 1432 if (entry == null) { 1433 break; 1434 } 1435 FlushDescriptor flush = WALEdit.getFlushDescriptor(entry.getEdit().getCells().get(0)); 1436 if (flush != null) { 1437 // do not replay flush 1438 } else { 1439 replayEdit(secondaryRegion, entry); 1440 } 1441 } 1442 1443 assertTrue(secondaryRegion.getMemStoreDataSize() > 0); 1444 1445 secondaryRegion.refreshStoreFiles(); 1446 1447 assertTrue(secondaryRegion.getMemStoreDataSize() == 0); 1448 1449 LOG.info("-- Verifying edits from primary"); 1450 verifyData(primaryRegion, 0, numRows, cq, families); 1451 LOG.info("-- Verifying edits from secondary"); 1452 verifyData(secondaryRegion, 0, numRows, cq, families); 1453 } 1454 1455 /** 1456 * Paths can be qualified or not. This does the assertion using String->Path conversion. 1457 */ 1458 private void assertPathListsEqual(List<String> list1, List<String> list2) { 1459 List<Path> l1 = new ArrayList<>(list1.size()); 1460 for (String path : list1) { 1461 l1.add(Path.getPathWithoutSchemeAndAuthority(new Path(path))); 1462 } 1463 List<Path> l2 = new ArrayList<>(list2.size()); 1464 for (String path : list2) { 1465 l2.add(Path.getPathWithoutSchemeAndAuthority(new Path(path))); 1466 } 1467 assertEquals(l1, l2); 1468 } 1469 1470 private void disableReads(HRegion region) { 1471 region.setReadsEnabled(false); 1472 try { 1473 verifyData(region, 0, 1, cq, families); 1474 fail("Should have failed with IOException"); 1475 } catch (IOException ex) { 1476 // expected 1477 } 1478 } 1479 1480 private void replay(HRegion region, Put put, long replaySeqId) throws IOException { 1481 put.setDurability(Durability.SKIP_WAL); 1482 MutationReplay mutation = new MutationReplay(MutationType.PUT, put, 0, 0); 1483 region.batchReplay(new MutationReplay[] { mutation }, replaySeqId); 1484 } 1485 1486 /** 1487 * Tests replaying region open markers from primary region. Checks whether the files are picked up 1488 */ 1489 @Test 1490 public void testReplayBulkLoadEvent() throws IOException { 1491 LOG.info("testReplayBulkLoadEvent starts"); 1492 putDataWithFlushes(primaryRegion, 100, 0, 100); // no flush 1493 1494 // close the region and open again. 1495 primaryRegion.close(); 1496 primaryRegion = HRegion.openHRegion(rootDir, primaryHri, htd, walPrimary, CONF, rss, null); 1497 1498 // bulk load a file into primary region 1499 byte[] randomValues = new byte[20]; 1500 Bytes.random(randomValues); 1501 Path testPath = TEST_UTIL.getDataTestDirOnTestFS(); 1502 1503 List<Pair<byte[], String>> familyPaths = new ArrayList<>(); 1504 int expectedLoadFileCount = 0; 1505 for (byte[] family : families) { 1506 familyPaths.add(new Pair<>(family, createHFileForFamilies(testPath, family, randomValues))); 1507 expectedLoadFileCount++; 1508 } 1509 primaryRegion.bulkLoadHFiles(familyPaths, false, null); 1510 1511 // now replay the edits and the bulk load marker 1512 reader = createWALReaderForPrimary(); 1513 1514 LOG.info("-- Replaying edits and region events in secondary"); 1515 BulkLoadDescriptor bulkloadEvent = null; 1516 while (true) { 1517 WAL.Entry entry = reader.next(); 1518 if (entry == null) { 1519 break; 1520 } 1521 bulkloadEvent = WALEdit.getBulkLoadDescriptor(entry.getEdit().getCells().get(0)); 1522 if (bulkloadEvent != null) { 1523 break; 1524 } 1525 } 1526 1527 // we should have 1 bulk load event 1528 assertTrue(bulkloadEvent != null); 1529 assertEquals(expectedLoadFileCount, bulkloadEvent.getStoresCount()); 1530 1531 // replay the bulk load event 1532 secondaryRegion.replayWALBulkLoadEventMarker(bulkloadEvent); 1533 1534 List<String> storeFileName = new ArrayList<>(); 1535 for (StoreDescriptor storeDesc : bulkloadEvent.getStoresList()) { 1536 storeFileName.addAll(storeDesc.getStoreFileList()); 1537 } 1538 // assert that the bulk loaded files are picked 1539 for (HStore s : secondaryRegion.getStores()) { 1540 for (HStoreFile sf : s.getStorefiles()) { 1541 storeFileName.remove(sf.getPath().getName()); 1542 } 1543 } 1544 assertTrue(storeFileName.isEmpty(), "Found some store file isn't loaded:" + storeFileName); 1545 1546 LOG.info("-- Verifying edits from secondary"); 1547 for (byte[] family : families) { 1548 assertGet(secondaryRegion, family, randomValues); 1549 } 1550 } 1551 1552 @Test 1553 public void testReplayingFlushCommitWithFileAlreadyDeleted() throws IOException { 1554 // tests replaying flush commit marker, but the flush file has already been compacted 1555 // from primary and also deleted from the archive directory 1556 secondaryRegion.replayWALFlushCommitMarker(FlushDescriptor.newBuilder() 1557 .setFlushSequenceNumber(Long.MAX_VALUE) 1558 .setTableName(UnsafeByteOperations 1559 .unsafeWrap(primaryRegion.getTableDescriptor().getTableName().getName())) 1560 .setAction(FlushAction.COMMIT_FLUSH) 1561 .setEncodedRegionName( 1562 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getEncodedNameAsBytes())) 1563 .setRegionName(UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getRegionName())) 1564 .addStoreFlushes(StoreFlushDescriptor.newBuilder() 1565 .setFamilyName(UnsafeByteOperations.unsafeWrap(families[0])) 1566 .setStoreHomeDir("/store_home_dir").addFlushOutput("/foo/baz/123").build()) 1567 .build()); 1568 } 1569 1570 @Test 1571 public void testReplayingCompactionWithFileAlreadyDeleted() throws IOException { 1572 // tests replaying compaction marker, but the compaction output file has already been compacted 1573 // from primary and also deleted from the archive directory 1574 secondaryRegion 1575 .replayWALCompactionMarker( 1576 CompactionDescriptor.newBuilder() 1577 .setTableName(UnsafeByteOperations 1578 .unsafeWrap(primaryRegion.getTableDescriptor().getTableName().getName())) 1579 .setEncodedRegionName( 1580 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getEncodedNameAsBytes())) 1581 .setFamilyName(UnsafeByteOperations.unsafeWrap(families[0])).addCompactionInput("/123") 1582 .addCompactionOutput("/456").setStoreHomeDir("/store_home_dir") 1583 .setRegionName( 1584 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getRegionName())) 1585 .build(), 1586 true, true, Long.MAX_VALUE); 1587 } 1588 1589 @Test 1590 public void testReplayingRegionOpenEventWithFileAlreadyDeleted() throws IOException { 1591 // tests replaying region open event marker, but the region files have already been compacted 1592 // from primary and also deleted from the archive directory 1593 secondaryRegion.replayWALRegionEventMarker(RegionEventDescriptor.newBuilder() 1594 .setTableName(UnsafeByteOperations 1595 .unsafeWrap(primaryRegion.getTableDescriptor().getTableName().getName())) 1596 .setEncodedRegionName( 1597 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getEncodedNameAsBytes())) 1598 .setRegionName(UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getRegionName())) 1599 .setEventType(EventType.REGION_OPEN) 1600 .setServer(ProtobufUtil.toServerName(ServerName.valueOf("foo", 1, 1))) 1601 .setLogSequenceNumber(Long.MAX_VALUE) 1602 .addStores( 1603 StoreDescriptor.newBuilder().setFamilyName(UnsafeByteOperations.unsafeWrap(families[0])) 1604 .setStoreHomeDir("/store_home_dir").addStoreFile("/123").build()) 1605 .build()); 1606 } 1607 1608 @Test 1609 public void testReplayingBulkLoadEventWithFileAlreadyDeleted() throws IOException { 1610 // tests replaying bulk load event marker, but the bulk load files have already been compacted 1611 // from primary and also deleted from the archive directory 1612 secondaryRegion.replayWALBulkLoadEventMarker(BulkLoadDescriptor.newBuilder() 1613 .setTableName( 1614 ProtobufUtil.toProtoTableName(primaryRegion.getTableDescriptor().getTableName())) 1615 .setEncodedRegionName( 1616 UnsafeByteOperations.unsafeWrap(primaryRegion.getRegionInfo().getEncodedNameAsBytes())) 1617 .setBulkloadSeqNum(Long.MAX_VALUE) 1618 .addStores( 1619 StoreDescriptor.newBuilder().setFamilyName(UnsafeByteOperations.unsafeWrap(families[0])) 1620 .setStoreHomeDir("/store_home_dir").addStoreFile("/123").build()) 1621 .build()); 1622 } 1623 1624 private String createHFileForFamilies(Path testPath, byte[] family, byte[] valueBytes) 1625 throws IOException { 1626 HFile.WriterFactory hFileFactory = HFile.getWriterFactoryNoCache(TEST_UTIL.getConfiguration()); 1627 // TODO We need a way to do this without creating files 1628 Path testFile = new Path(testPath, TEST_UTIL.getRandomUUID().toString()); 1629 FSDataOutputStream out = TEST_UTIL.getTestFileSystem().create(testFile); 1630 try { 1631 hFileFactory.withOutputStream(out); 1632 hFileFactory.withFileContext(new HFileContextBuilder().build()); 1633 HFile.Writer writer = hFileFactory.create(); 1634 try { 1635 writer.append(new KeyValue(ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY) 1636 .setRow(valueBytes).setFamily(family).setQualifier(valueBytes).setTimestamp(0L) 1637 .setType(KeyValue.Type.Put.getCode()).setValue(valueBytes).build())); 1638 } finally { 1639 writer.close(); 1640 } 1641 } finally { 1642 out.close(); 1643 } 1644 return testFile.toString(); 1645 } 1646 1647 /** 1648 * Puts a total of numRows + numRowsAfterFlush records indexed with numeric row keys. Does a flush 1649 * every flushInterval number of records. Then it puts numRowsAfterFlush number of more rows but 1650 * does not execute flush after 1651 */ 1652 private void putDataWithFlushes(HRegion region, int flushInterval, int numRows, 1653 int numRowsAfterFlush) throws IOException { 1654 int start = 0; 1655 for (; start < numRows; start += flushInterval) { 1656 LOG.info("-- Writing some data to primary from " + start + " to " + (start + flushInterval)); 1657 putData(region, Durability.SYNC_WAL, start, flushInterval, cq, families); 1658 LOG.info("-- Flushing primary, creating 3 files for 3 stores"); 1659 region.flush(true); 1660 } 1661 LOG.info("-- Writing some more data to primary, not flushing"); 1662 putData(region, Durability.SYNC_WAL, start, numRowsAfterFlush, cq, families); 1663 } 1664 1665 private void putDataByReplay(HRegion region, int startRow, int numRows, byte[] qf, 1666 byte[]... families) throws IOException { 1667 for (int i = startRow; i < startRow + numRows; i++) { 1668 Put put = new Put(Bytes.toBytes("" + i)); 1669 put.setDurability(Durability.SKIP_WAL); 1670 for (byte[] family : families) { 1671 put.addColumn(family, qf, EnvironmentEdgeManager.currentTime(), null); 1672 } 1673 replay(region, put, i + 1); 1674 } 1675 } 1676 1677 private static HRegion initHRegion(byte[] tableName, byte[]... families) throws IOException { 1678 return TEST_UTIL.createLocalHRegion(TableName.valueOf(tableName), HConstants.EMPTY_START_ROW, 1679 HConstants.EMPTY_END_ROW, CONF, false, Durability.SYNC_WAL, null, families); 1680 } 1681}