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 */ 018 019package org.apache.hadoop.hbase.client; 020 021import static junit.framework.TestCase.assertTrue; 022import static org.junit.Assert.assertEquals; 023 024import java.util.Arrays; 025import java.util.List; 026import java.util.stream.Collectors; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseTestingUtility; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.master.HMaster; 032import org.apache.hadoop.hbase.master.RegionState; 033import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv; 034import org.apache.hadoop.hbase.master.procedure.TableProcedureInterface; 035import org.apache.hadoop.hbase.procedure2.Procedure; 036import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 037import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException; 038import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 039import org.apache.hadoop.hbase.regionserver.HRegionServer; 040import org.apache.hadoop.hbase.testclassification.ClientTests; 041import org.apache.hadoop.hbase.testclassification.LargeTests; 042import org.apache.hadoop.hbase.util.Bytes; 043import org.apache.hadoop.hbase.util.Threads; 044import org.junit.AfterClass; 045import org.junit.BeforeClass; 046import org.junit.ClassRule; 047import org.junit.Rule; 048import org.junit.Test; 049import org.junit.experimental.categories.Category; 050import org.junit.rules.TestName; 051import org.junit.runner.RunWith; 052import org.junit.runners.Parameterized; 053import org.junit.runners.Parameterized.Parameter; 054import org.junit.runners.Parameterized.Parameters; 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058import org.apache.hbase.thirdparty.com.google.common.io.Closeables; 059 060import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 061 062/** 063 * Class to test HBaseHbck. 064 * Spins up the minicluster once at test start and then takes it down afterward. 065 * Add any testing of HBaseHbck functionality here. 066 */ 067@RunWith(Parameterized.class) 068@Category({LargeTests.class, ClientTests.class}) 069public class TestHbck { 070 @ClassRule 071 public static final HBaseClassTestRule CLASS_RULE = 072 HBaseClassTestRule.forClass(TestHbck.class); 073 074 private static final Logger LOG = LoggerFactory.getLogger(TestHbck.class); 075 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 076 077 @Rule 078 public TestName name = new TestName(); 079 080 @Parameter 081 public boolean async; 082 083 private static final TableName TABLE_NAME = TableName.valueOf(TestHbck.class.getSimpleName()); 084 085 private static ProcedureExecutor<MasterProcedureEnv> procExec; 086 087 private static AsyncConnection ASYNC_CONN; 088 089 @Parameters(name = "{index}: async={0}") 090 public static List<Object[]> params() { 091 return Arrays.asList(new Object[] { false }, new Object[] { true }); 092 } 093 094 private Hbck getHbck() throws Exception { 095 if (async) { 096 return ASYNC_CONN.getHbck().get(); 097 } else { 098 return TEST_UTIL.getHbck(); 099 } 100 } 101 102 @BeforeClass 103 public static void setUpBeforeClass() throws Exception { 104 TEST_UTIL.startMiniCluster(3); 105 TEST_UTIL.createMultiRegionTable(TABLE_NAME, Bytes.toBytes("family1"), 5); 106 procExec = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterProcedureExecutor(); 107 ASYNC_CONN = ConnectionFactory.createAsyncConnection(TEST_UTIL.getConfiguration()).get(); 108 } 109 110 @AfterClass 111 public static void tearDownAfterClass() throws Exception { 112 Closeables.close(ASYNC_CONN, true); 113 TEST_UTIL.shutdownMiniCluster(); 114 } 115 116 public static class SuspendProcedure extends 117 ProcedureTestingUtility.NoopProcedure<MasterProcedureEnv> implements TableProcedureInterface { 118 public SuspendProcedure() { 119 super(); 120 } 121 122 @Override 123 protected Procedure[] execute(final MasterProcedureEnv env) 124 throws ProcedureSuspendedException { 125 // Always suspend the procedure 126 throw new ProcedureSuspendedException(); 127 } 128 129 @Override 130 public TableName getTableName() { 131 return TABLE_NAME; 132 } 133 134 @Override 135 public TableOperationType getTableOperationType() { 136 return TableOperationType.READ; 137 } 138 } 139 140 @Test 141 public void testBypassProcedure() throws Exception { 142 // SuspendProcedure 143 final SuspendProcedure proc = new SuspendProcedure(); 144 long procId = procExec.submitProcedure(proc); 145 Thread.sleep(500); 146 147 //bypass the procedure 148 List<Long> pids = Arrays.<Long>asList(procId); 149 List<Boolean> results = getHbck().bypassProcedure(pids, 30000, false, false); 150 assertTrue("Failed to by pass procedure!", results.get(0)); 151 TEST_UTIL.waitFor(5000, () -> proc.isSuccess() && proc.isBypass()); 152 LOG.info("{} finished", proc); 153 } 154 155 @Test 156 public void testSetTableStateInMeta() throws Exception { 157 Hbck hbck = getHbck(); 158 // set table state to DISABLED 159 hbck.setTableStateInMeta(new TableState(TABLE_NAME, TableState.State.DISABLED)); 160 // Method {@link Hbck#setTableStateInMeta()} returns previous state, which in this case 161 // will be DISABLED 162 TableState prevState = 163 hbck.setTableStateInMeta(new TableState(TABLE_NAME, TableState.State.ENABLED)); 164 assertTrue("Incorrect previous state! expeced=DISABLED, found=" + prevState.getState(), 165 prevState.isDisabled()); 166 } 167 168 @Test 169 public void testAssigns() throws Exception { 170 Hbck hbck = getHbck(); 171 try (Admin admin = TEST_UTIL.getConnection().getAdmin()) { 172 List<RegionInfo> regions = admin.getRegions(TABLE_NAME); 173 for (RegionInfo ri: regions) { 174 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 175 getRegionStates().getRegionState(ri.getEncodedName()); 176 LOG.info("RS: {}", rs.toString()); 177 } 178 List<Long> pids = hbck.unassigns(regions.stream().map(r -> r.getEncodedName()). 179 collect(Collectors.toList())); 180 waitOnPids(pids); 181 for (RegionInfo ri: regions) { 182 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 183 getRegionStates().getRegionState(ri.getEncodedName()); 184 LOG.info("RS: {}", rs.toString()); 185 assertTrue(rs.toString(), rs.isClosed()); 186 } 187 pids = hbck.assigns(regions.stream().map(r -> r.getEncodedName()). 188 collect(Collectors.toList())); 189 waitOnPids(pids); 190 for (RegionInfo ri: regions) { 191 RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager(). 192 getRegionStates().getRegionState(ri.getEncodedName()); 193 LOG.info("RS: {}", rs.toString()); 194 assertTrue(rs.toString(), rs.isOpened()); 195 } 196 // What happens if crappy region list passed? 197 pids = hbck.assigns(Arrays.stream(new String [] {"a", "some rubbish name"}). 198 collect(Collectors.toList())); 199 for (long pid: pids) { 200 assertEquals(org.apache.hadoop.hbase.procedure2.Procedure.NO_PROC_ID, pid); 201 } 202 } 203 } 204 205 @Test 206 public void testScheduleSCP() throws Exception { 207 HRegionServer testRs = TEST_UTIL.getRSForFirstRegionInTable(TABLE_NAME); 208 TEST_UTIL.loadTable(TEST_UTIL.getConnection().getTable(TABLE_NAME), Bytes.toBytes("family1"), 209 true); 210 ServerName serverName = testRs.getServerName(); 211 Hbck hbck = getHbck(); 212 List<Long> pids = 213 hbck.scheduleServerCrashProcedure(Arrays.asList(ProtobufUtil.toServerName(serverName))); 214 assertTrue(pids.get(0) > 0); 215 LOG.info("pid is {}", pids.get(0)); 216 217 pids = hbck.scheduleServerCrashProcedure(Arrays.asList(ProtobufUtil.toServerName(serverName))); 218 assertTrue(pids.get(0) == -1); 219 LOG.info("pid is {}", pids.get(0)); 220 } 221 222 @Test 223 public void testRunHbckChore() throws Exception { 224 HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster(); 225 long endTimestamp = master.getHbckChore().getCheckingEndTimestamp(); 226 Hbck hbck = getHbck(); 227 boolean ran = false; 228 while (!ran) { 229 ran = hbck.runHbckChore(); 230 if (ran) { 231 assertTrue(master.getHbckChore().getCheckingEndTimestamp() > endTimestamp); 232 } 233 } 234 } 235 236 private void waitOnPids(List<Long> pids) { 237 for (Long pid: pids) { 238 while (!TEST_UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(). 239 isFinished(pid)) { 240 Threads.sleep(100); 241 } 242 } 243 } 244}