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.junit.Assert.assertArrayEquals; 021import static org.junit.Assert.assertTrue; 022import static org.mockito.ArgumentMatchers.any; 023import static org.mockito.Mockito.doAnswer; 024import static org.mockito.Mockito.spy; 025 026import java.io.IOException; 027import java.util.Map; 028import org.apache.commons.lang3.mutable.MutableBoolean; 029import org.apache.hadoop.hbase.DroppedSnapshotException; 030import org.apache.hadoop.hbase.HBaseClassTestRule; 031import org.apache.hadoop.hbase.HBaseTestingUtility; 032import org.apache.hadoop.hbase.HConstants; 033import org.apache.hadoop.hbase.NamespaceDescriptor; 034import org.apache.hadoop.hbase.TableName; 035import org.apache.hadoop.hbase.client.Admin; 036import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 037import org.apache.hadoop.hbase.client.Connection; 038import org.apache.hadoop.hbase.client.Get; 039import org.apache.hadoop.hbase.client.Put; 040import org.apache.hadoop.hbase.client.Result; 041import org.apache.hadoop.hbase.client.Table; 042import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 043import org.apache.hadoop.hbase.regionserver.HRegion.FlushResult; 044import org.apache.hadoop.hbase.testclassification.LargeTests; 045import org.apache.hadoop.hbase.util.Bytes; 046import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 047import org.junit.After; 048import org.junit.Before; 049import org.junit.ClassRule; 050import org.junit.Test; 051import org.junit.experimental.categories.Category; 052import org.mockito.invocation.InvocationOnMock; 053import org.mockito.stubbing.Answer; 054import org.slf4j.Logger; 055import org.slf4j.LoggerFactory; 056 057/** 058 * Testcase for https://issues.apache.org/jira/browse/HBASE-13811 059 */ 060@Category({ LargeTests.class }) 061public class TestSplitWalDataLoss { 062 063 @ClassRule 064 public static final HBaseClassTestRule CLASS_RULE = 065 HBaseClassTestRule.forClass(TestSplitWalDataLoss.class); 066 067 private static final Logger LOG = LoggerFactory.getLogger(TestSplitWalDataLoss.class); 068 069 private final HBaseTestingUtility testUtil = new HBaseTestingUtility(); 070 071 private NamespaceDescriptor namespace = 072 NamespaceDescriptor.create(getClass().getSimpleName()).build(); 073 074 private TableName tableName = TableName.valueOf(namespace.getName(), "dataloss"); 075 076 private byte[] family = Bytes.toBytes("f"); 077 078 private byte[] qualifier = Bytes.toBytes("q"); 079 080 @Before 081 public void setUp() throws Exception { 082 testUtil.getConfiguration().setInt("hbase.regionserver.msginterval", 30000); 083 testUtil.startMiniCluster(2); 084 Admin admin = testUtil.getAdmin(); 085 admin.createNamespace(namespace); 086 admin.createTable(TableDescriptorBuilder.newBuilder(tableName) 087 .setColumnFamily(ColumnFamilyDescriptorBuilder.of(family)).build()); 088 testUtil.waitTableAvailable(tableName); 089 } 090 091 @After 092 public void tearDown() throws Exception { 093 testUtil.shutdownMiniCluster(); 094 } 095 096 @Test 097 public void test() throws IOException, InterruptedException { 098 final HRegionServer rs = testUtil.getRSForFirstRegionInTable(tableName); 099 final HRegion region = (HRegion) rs.getRegions(tableName).get(0); 100 HRegion spiedRegion = spy(region); 101 final MutableBoolean flushed = new MutableBoolean(false); 102 final MutableBoolean reported = new MutableBoolean(false); 103 doAnswer(new Answer<FlushResult>() { 104 @Override 105 public FlushResult answer(InvocationOnMock invocation) throws Throwable { 106 synchronized (flushed) { 107 flushed.setValue(true); 108 flushed.notifyAll(); 109 } 110 synchronized (reported) { 111 while (!reported.booleanValue()) { 112 reported.wait(); 113 } 114 } 115 rs.getWAL(region.getRegionInfo()) 116 .abortCacheFlush(region.getRegionInfo().getEncodedNameAsBytes()); 117 throw new DroppedSnapshotException("testcase"); 118 } 119 }).when(spiedRegion).internalFlushCacheAndCommit(any(), any(), any(), any()); 120 // Find region key; don't pick up key for hbase:meta by mistake. 121 String key = null; 122 for (Map.Entry<String, HRegion> entry : rs.getOnlineRegions().entrySet()) { 123 if (entry.getValue().getRegionInfo().getTable().equals(this.tableName)) { 124 key = entry.getKey(); 125 break; 126 } 127 } 128 rs.getOnlineRegions().put(key, spiedRegion); 129 Connection conn = testUtil.getConnection(); 130 131 try (Table table = conn.getTable(tableName)) { 132 table.put(new Put(Bytes.toBytes("row0")).addColumn(family, qualifier, Bytes.toBytes("val0"))); 133 } 134 long oldestSeqIdOfStore = region.getOldestSeqIdOfStore(family); 135 LOG.info("CHANGE OLDEST " + oldestSeqIdOfStore); 136 assertTrue(oldestSeqIdOfStore > HConstants.NO_SEQNUM); 137 rs.getMemStoreFlusher().requestFlush(spiedRegion, FlushLifeCycleTracker.DUMMY); 138 synchronized (flushed) { 139 while (!flushed.booleanValue()) { 140 flushed.wait(); 141 } 142 } 143 try (Table table = conn.getTable(tableName)) { 144 table.put(new Put(Bytes.toBytes("row1")).addColumn(family, qualifier, Bytes.toBytes("val1"))); 145 } 146 long now = EnvironmentEdgeManager.currentTime(); 147 rs.tryRegionServerReport(now - 500, now); 148 synchronized (reported) { 149 reported.setValue(true); 150 reported.notifyAll(); 151 } 152 while (testUtil.getRSForFirstRegionInTable(tableName) == rs) { 153 Thread.sleep(100); 154 } 155 try (Table table = conn.getTable(tableName)) { 156 Result result = table.get(new Get(Bytes.toBytes("row0"))); 157 assertArrayEquals(Bytes.toBytes("val0"), result.getValue(family, qualifier)); 158 } 159 } 160}