HBASE-20169 NPE when calling HBTU.shutdownMiniCluster
Adds a prepare step to RecoverMetaProcedure in which we test for cluster up and master being up. If not up, we fail the run. Modified hbase-server/src/main/java/org/apache/hadoop/hbase/master/cleaner/HFileCleaner.java Modified hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java Minor log cleanup. Modified hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/RecoverMetaProcedure.java Add pepare step. Modified hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestAssignmentManagerMetrics.java Debug for the failing test.... Added hbase-server/src/test/java/org/apache/hadoop/hbase/master/procedure/TestRecoverMetaProcedure.java Test the prepare step goes down if master or cluster are down.
This commit is contained in:
parent
75ff2504ec
commit
fabb1d97cc
|
@ -74,7 +74,8 @@ public abstract class StateMachineProcedure<TEnvironment, TState>
|
||||||
*/
|
*/
|
||||||
private int previousState;
|
private int previousState;
|
||||||
|
|
||||||
protected enum Flow {
|
@VisibleForTesting
|
||||||
|
public enum Flow {
|
||||||
HAS_MORE_STATE,
|
HAS_MORE_STATE,
|
||||||
NO_MORE_STATE,
|
NO_MORE_STATE,
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,6 +307,7 @@ enum ServerCrashState {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RecoverMetaState {
|
enum RecoverMetaState {
|
||||||
|
RECOVER_META_PREPARE = 0;
|
||||||
RECOVER_META_SPLIT_LOGS = 1;
|
RECOVER_META_SPLIT_LOGS = 1;
|
||||||
RECOVER_META_ASSIGN_REGIONS = 2;
|
RECOVER_META_ASSIGN_REGIONS = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,12 +235,12 @@ public class HFileCleaner extends CleanerChore<BaseHFileCleanerDelegate> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
LOG.debug("Removing: {} from archive", task.filePath);
|
LOG.debug("Removing {}", task.filePath);
|
||||||
boolean succeed;
|
boolean succeed;
|
||||||
try {
|
try {
|
||||||
succeed = this.fs.delete(task.filePath, false);
|
succeed = this.fs.delete(task.filePath, false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.warn("Failed to delete file {}", task.filePath, e);
|
LOG.warn("Failed to delete {}", task.filePath, e);
|
||||||
succeed = false;
|
succeed = false;
|
||||||
}
|
}
|
||||||
task.setResult(succeed);
|
task.setResult(succeed);
|
||||||
|
@ -250,7 +250,7 @@ public class HFileCleaner extends CleanerChore<BaseHFileCleanerDelegate> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
LOG.debug("Exit thread: {}", Thread.currentThread());
|
LOG.debug("Exit {}", Thread.currentThread());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,21 @@ public class RecoverMetaProcedure
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case RECOVER_META_PREPARE:
|
||||||
|
// If Master is going down or cluster is up, skip this assign by returning NO_MORE_STATE
|
||||||
|
if (!master.isClusterUp()) {
|
||||||
|
String msg = "Cluster not up! Skipping hbase:meta assign.";
|
||||||
|
LOG.warn(msg);
|
||||||
|
return Flow.NO_MORE_STATE;
|
||||||
|
}
|
||||||
|
if (master.isStopping() || master.isStopped()) {
|
||||||
|
String msg = "Master stopping=" + master.isStopping() + ", stopped=" +
|
||||||
|
master.isStopped() + "; skipping hbase:meta assign.";
|
||||||
|
LOG.warn(msg);
|
||||||
|
return Flow.NO_MORE_STATE;
|
||||||
|
}
|
||||||
|
setNextState(RecoverMetaState.RECOVER_META_SPLIT_LOGS);
|
||||||
|
break;
|
||||||
case RECOVER_META_SPLIT_LOGS:
|
case RECOVER_META_SPLIT_LOGS:
|
||||||
LOG.info("Start " + this);
|
LOG.info("Start " + this);
|
||||||
if (shouldSplitWal) {
|
if (shouldSplitWal) {
|
||||||
|
@ -202,7 +217,7 @@ public class RecoverMetaProcedure
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MasterProcedureProtos.RecoverMetaState getInitialState() {
|
protected MasterProcedureProtos.RecoverMetaState getInitialState() {
|
||||||
return RecoverMetaState.RECOVER_META_SPLIT_LOGS;
|
return RecoverMetaState.RECOVER_META_PREPARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -424,7 +424,7 @@ public class ChunkCreator {
|
||||||
long created = chunkCount.get();
|
long created = chunkCount.get();
|
||||||
long reused = reusedChunkCount.sum();
|
long reused = reusedChunkCount.sum();
|
||||||
long total = created + reused;
|
long total = created + reused;
|
||||||
LOG.debug("{} Stats (chunk size={}): current pool size={}, created chunk count={}, " +
|
LOG.debug("{} stats (chunk size={}): current pool size={}, created chunk count={}, " +
|
||||||
"reused chunk count={}, reuseRatio={}", label, chunkSize, reclaimedChunks.size(),
|
"reused chunk count={}, reuseRatio={}", label, chunkSize, reclaimedChunks.size(),
|
||||||
created, reused,
|
created, reused,
|
||||||
(total == 0? "0": StringUtils.formatPercent((float)reused/(float)total,2)));
|
(total == 0? "0": StringUtils.formatPercent((float)reused/(float)total,2)));
|
||||||
|
|
|
@ -98,6 +98,7 @@ public class TestAssignmentManagerMetrics {
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void after() throws Exception {
|
public static void after() throws Exception {
|
||||||
|
LOG.info("AFTER {} <= IS THIS NULL?", TEST_UTIL);
|
||||||
TEST_UTIL.shutdownMiniCluster();
|
TEST_UTIL.shutdownMiniCluster();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hbase.master.procedure;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.hadoop.hbase.HBaseClassTestRule;
|
||||||
|
import org.apache.hadoop.hbase.HBaseTestingUtility;
|
||||||
|
import org.apache.hadoop.hbase.master.MasterServices;
|
||||||
|
import org.apache.hadoop.hbase.master.assignment.MockMasterServices;
|
||||||
|
import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
|
||||||
|
import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
|
||||||
|
import org.apache.hadoop.hbase.procedure2.StateMachineProcedure;
|
||||||
|
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.MasterTests;
|
||||||
|
import org.apache.hadoop.hbase.testclassification.SmallTests;
|
||||||
|
import org.junit.ClassRule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.experimental.categories.Category;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@Category({MasterTests.class, SmallTests.class})
|
||||||
|
public class TestRecoverMetaProcedure {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(TestRecoverMetaProcedure.class);
|
||||||
|
@ClassRule
|
||||||
|
public static final HBaseClassTestRule CLASS_RULE =
|
||||||
|
HBaseClassTestRule.forClass(TestRecoverMetaProcedure.class);
|
||||||
|
private static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the new prepare step.
|
||||||
|
* Here we test that our Mock is faking out the precedure well-enough for it to progress past the
|
||||||
|
* first prepare stage.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrepare() throws ProcedureSuspendedException, ProcedureYieldException,
|
||||||
|
InterruptedException, IOException {
|
||||||
|
RecoverMetaProcedure rmp = new RecoverMetaProcedure();
|
||||||
|
MasterProcedureEnv env = Mockito.mock(MasterProcedureEnv.class);
|
||||||
|
MasterServices masterServices =
|
||||||
|
new MockMasterServices(UTIL.getConfiguration(), null);
|
||||||
|
Mockito.when(env.getMasterServices()).thenReturn(masterServices);
|
||||||
|
assertEquals(StateMachineProcedure.Flow.HAS_MORE_STATE,
|
||||||
|
rmp.executeFromState(env, rmp.getInitialState()));
|
||||||
|
int stateId = rmp.getCurrentStateId();
|
||||||
|
assertEquals(MasterProcedureProtos.RecoverMetaState.RECOVER_META_SPLIT_LOGS_VALUE,
|
||||||
|
rmp.getCurrentStateId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the new prepare step.
|
||||||
|
* If Master is stopping, procedure should skip the assign by returning NO_MORE_STATE
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrepareWithMasterStopping() throws ProcedureSuspendedException,
|
||||||
|
ProcedureYieldException, InterruptedException, IOException {
|
||||||
|
RecoverMetaProcedure rmp = new RecoverMetaProcedure();
|
||||||
|
MasterProcedureEnv env = Mockito.mock(MasterProcedureEnv.class);
|
||||||
|
MasterServices masterServices = new MockMasterServices(UTIL.getConfiguration(), null) {
|
||||||
|
@Override
|
||||||
|
public boolean isStopping() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Mockito.when(env.getMasterServices()).thenReturn(masterServices);
|
||||||
|
assertEquals(StateMachineProcedure.Flow.NO_MORE_STATE,
|
||||||
|
rmp.executeFromState(env, rmp.getInitialState()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the new prepare step.
|
||||||
|
* If cluster is down, procedure should skip the assign by returning NO_MORE_STATE
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrepareWithNoCluster() throws ProcedureSuspendedException,
|
||||||
|
ProcedureYieldException, InterruptedException, IOException {
|
||||||
|
RecoverMetaProcedure rmp = new RecoverMetaProcedure();
|
||||||
|
MasterProcedureEnv env = Mockito.mock(MasterProcedureEnv.class);
|
||||||
|
MasterServices masterServices = new MockMasterServices(UTIL.getConfiguration(), null) {
|
||||||
|
@Override
|
||||||
|
public boolean isClusterUp() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Mockito.when(env.getMasterServices()).thenReturn(masterServices);
|
||||||
|
assertEquals(StateMachineProcedure.Flow.NO_MORE_STATE,
|
||||||
|
rmp.executeFromState(env, rmp.getInitialState()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue